多线程并发出现异常的情况
单例模式
public class DoubleCheckSingleton { /** * 使用volatile,在多线程场景下,确保在判断null时,对所有线程可见 */ private static volatile DoubleCheckSingleton uniqInstance; /** * 构造器私有,防止外部实例化该类 */ private DoubleCheckSingleton() {} /** * 静态方法实例化,由于在类内部,可以调用构造器 */ public static DoubleCheckSingleton getInstance(){ if (null == uniqInstance) { // 此处判断需要可见性volatile synchronized (DoubleCheckSingleton.class) { if (null == uniqInstance) { //延迟初始化 uniqInstance = new DoubleCheckSingleton(); } } } return uniqInstance; } }
可见性
- 引发原因
CPU高速缓存 由于各个线程会在执行是从 主存 加载到CPU高速缓存中执行,节省读取内存时间(CPU速度>> 主存速度)
线程A对共享变量V做了修改,其它线程B看到V的值还是之前的old失效数据
- 后果(以单例模式举例)
失效数据
线程A已经创建了instance,但是线程B读取的instance还是null,会导致创建了两个instance,A和B拿到的实例不一样!!
失效值可能导致错误的结果或者导致活跃性问题。
- fix方案
volatile
加锁(syn、lock)
有序性
- 引发原因
编译优化之指令重排序
CPU执行指令时会有一些指令重排序以期最大效率
- 后果(以单例模式举例)
单例模式赋值和实例化的重排序导致的异常
- fix方案
volatile
加锁
通过Happens-before规则实现
内置锁的释放锁操作发生在该锁随后的加锁操作之前
一个volatile变量的写操作发生在这个volatile变量随后的读操作之前
原子性
- 引发原因
线程切换
CPU调度是时间片轮转如下图
public方法如有对共享变量读取-修改-写入等类型有依赖的操作序列时,需要是原子性完成
自增、先检查后执行