用AI赚第一桶💰低成本搭建一套AI赚钱工具,源码可二开。 广告
欢迎关注我的公众号: ![我的公众号](https://markdown-1258186581.cos.ap-shanghai.myqcloud.com/20190606104746.png) ## 什么是线程安全? ![](https://markdown-1258186581.cos.ap-shanghai.myqcloud.com/20190610101014.png) ## volatile 关键字 保证了有序性,可见性,但是没保证原子性。 由于java的内存模型的原因,线程在修改了共享变量后并不会立即把修改同步到内存中,而是会保存到线程的本地缓存中。 **volatile关键字修饰的变量在线程修改后会立刻同步到主内存中,使该修改对其他线程可见** ## Synchronized 关键字 * sychronized 是java中的内置锁,可以限制线程对代码块或者方法的访问 * sychronized可以修饰类方法,实例方法,代码块 * 在执行sychronized方法或代码块时,线程需要先获取被修饰对象的锁。一次只能有一个线程可以获取到一个对象的锁,同一个线程可以多次获取同一个对象的锁(可重入锁) * sychronized 不能响应中断,当一个线程在等待锁的时候,调用该线程的interrupt是不起作用的 * 锁的获取和释放是隐式的,进入同步sychronized blocks后会获取锁,离开sychronized blocks后会释放锁 ## Obejct类的wait/notify方法 * wait/notify是用于线程同步的方法 * wait方法会使得当前线程放弃调用对象的监控,并使当前线程进入等待。直到调用了该对象的notify方法或者notifyAll方法(语法上是这样设计,但存在例外) * 可以多次调用对象的wait方法,notify方法只会随机释放一个wait方法等待,与调用顺序无关。如果要释放所有的wait调用可以调用notifyAll方法 * 调用wait的线程有可能会存在interrupt,虚假唤醒的情况,导致wait方法返回,但实际并没有调用对象的notify方法。在使用时通常会搭配一个lock flag和loop使用 ## ThreadLocal 实现 ThreadLocal实例通常作为静态的私有的(private static)字段出现在一个类中,这个类用来关联一个线程。ThreadLocal是一个线程级别的局部变量,下面是线程局部变量(ThreadLocal variables)的关键点: 1. 当使用ThreadLocal维护变量时,若多个线程访问ThreadLocal实例,ThreadLocal为每个使用该变量的线程提供了一个独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其他线程所对应的副本。 2. 从线程的角度看,目标变量就像是线程的本地变量,这也是类名中Local所要表达的意思。 首先:ThreadLocal 是一个泛型类,内部有个静态内部类 ThreadLocalMap,使用弱引用的方式保存 ThreadLocal。 在每个线程内部有一个`ThreadLocal.ThreadLocalMap threadLocals = null;`, 这个 map 的 key 就是每个线程的实例. 在 get 或者 put 的时候,会先通过 getMap 拿当前线程绑定的 ThreadLocalMap 对象,如果没有,会创建一个新的对象。以 ThreadLocal 为 key,以泛型为 value。 这样,在访问 ThreadLocal 类的时候,都会通过拿其内部的 ThreadLocalMap,然后再去获得设置的泛型值。 所以就导致,不同的类在内部设置 ThreadLocalMap 以后,确保能够保证同个线程中值是唯一的。 [参考地址](https://www.cnblogs.com/studyLog-share/p/5295557.html) ## 重入锁实现线程同步 Lock,一般使用其实现类 ReentrantLock。 ReentrantLock获取锁定与三种方式: 1. lock(), 如果获取了锁立即返回,如果别的线程持有锁,当前线程则一直处于休眠状态,直到获取锁 2. tryLock(), 如果获取了锁立即返回true,如果别的线程正持有锁,立即返回false; 3. tryLock(long timeout,TimeUnit unit), 如果获取了锁定立即返回true,如果别的线程正持有锁,会等待参数给定的时间,在等待的过程中,如果获取了锁定,就返回true,如果等待超时,返回false; 4. lockInterruptibly:如果获取了锁定立即返回,如果没有获取锁定,当前线程处于休眠状态,直到或者锁定,或者当前线程被别的线程中断 ReentrantLock 和 Synchronized 的区别: 线程A和B都要获取对象O的锁定,假设A获取了对象O锁,B将等待A释放对O的锁定, - 如果使用 synchronized ,如果A不释放,B将一直等下去,不能被中断 - 如果 使用ReentrantLock,如果A不释放,可以使B在等待了足够长的时间以后,中断等待,而干别的事情