Volatile关键字
Java 多线程需要解决三个问题:
- 原子性:保证指令不会受到线程上下文切换的影响
- 可见性:保证指令不会受到 CPU 缓存的影响
- 有序性:保证指令不会受到 CPU 指令重排序和 JIT 即时编译器的指令重排序的影响
其中,原子性通过synchronized
关键字(锁)来实现;而可见性和有序性则通过volatile
关键字来实现(也可以通过synchronized
来实现)。
Java内存模型造成的可见性问题
指令重排序造成的有序性问题
指令重排序现象
int x = 1;
int y = 2;
// 没有相互依赖关系,可能发生指令重排序
int y = 2;
int x = 1;
int x = 1;
int y = x - 1;
// 这种情况下不会发生指令重排序
潜在问题演示
Volatile的实现原理
volatile 通过读写屏障来实现在多线程环境下共享变量的可见性和有序性。
写屏障
- 写屏障之前执行的代码,对共享变量的修改都会立即同步到主内存中(可见性保证之一)
- 写屏障之前的代码不会发生重排序(有序性保证之一)
读屏障
- 读屏障之后执行的代码,对共享变量的读取都必须从主内存中获取最新值,而不能使用工作内存中的缓存之(可见性保证之一)
- 读屏障之后的代码不会发生重排序(有序性保证之一)
双重检测锁机制的完善(DCL)
双重检测锁