一、什么是线程安全?
若是一个对象构造完成后,调用者无需额外的操做,就能够在多线程环境下随意地使用,而且不发生错误,那么这个对象就是线程安全的。安全
二、线程安全的注意事项
- 对『线程安全性』的讨论必须创建在对象内部存在共享变量这一前提,若对象在多条线程间没有共享数据,那这个对象必定是线程安全的!
- 咱们一般所说的『线程安全』即为『相对的线程安全』,JDK中标注为线程安全的类一般就是『相对的线程安全』
三、实现线程安全的几种方法
- 互斥同步
- 同步是指在同一时刻只能由一个线程操做共享变量
- 互斥会引发阻塞,当一条线程请求一个已经被另外一线程使用的锁时,就会进入阻塞态;而进入阻塞态会涉及上下文切换。所以,使用互斥来实现同步的开销是很大的。
- 互斥同步(阻塞式同步)是一种『悲观锁』,即它认为老是存在多条线程竞争资源的状况,所以它无论当前是否是真的有多条线程在竞争共享资源,它老是先上锁,而后再处理。
- Java中有两种实现互斥同步的方式:synchronized和ReentrantLock。
- 非阻塞同步
- 它是一种『乐观锁』,即它老是认为当前没有线程使用共享资源,所以它无论当前的状态,直接操做共享资源,若发现产生了冲突,那么再采起补偿措施(如:CAS的补偿措施就是不断尝试,直到不发生冲突为止),这种方式线程无需进入阻塞态(挂起态),所以称为『非阻塞同步』。
- JUC中各类整形原子类的自增、自减等操做就使用了CAS。
- CAS操做过程:CAS操做存在3个值:共享变量V、预期的旧值A、新值B,若V与A相同,则将V更新成B,不然就不更新,继续循环比较,直到更新完成为止。
- CAS操做可能引起的问题:ABA问题。 若V一开始的值为A,但在准备赋新值的过程当中A变成了B,又变成了A,而CAS操做误认为V没有被改过。