volatile -- 最轻量级的同步机制
特性
- 保证变量对所有线程的可见性 -- 即当一条线程改变了该变量的值,其他线程立刻得知
- 禁止了指令重排序优化
Java内存模型实现volatile
load + use 必须连续一起出现,这就保证了线程从主内存读到的值是最新的值
assign + store + write必须连续一起出现,这就保证了线程修改的值必须立刻更新到主内存
对于两个变量A和B,如果先对A执行了use或assign操作,那么就要比对B先执行read或write操作,这保证了指令不能重排序
并发不安全
虽然volatile变量的值一旦修改就能立刻得知,但是它的运算操作需要时间,在这段时间内变量的值可能被修改,因此不安全
如何保证线程安全?
只能用synchornized或者是Lock类实现同步
适用情况
- boolean flag情景,使用bool变量作为开关
- 双锁单例模式中使用volatile来保证实现唯一实例:如果没有volatile,线程1new获取实例的信息没有立刻得到更新且放开了synchronized锁,其他线程就会因为实例 == null继续new
指令重排序
普通的变量只保证需要赋值的变量能得到正确结果而不保证指令执行顺序
意义
JVM能够根据处理器的特性(CPU的多级缓存系统、多核处理器等)适当的重新排序机器指令,使机器指令更符合CPU的执行特点,最大限度的发挥机器的性能
内存屏障
重排序时不能把后面的指令重排序到内存屏障之前,通过给指令加lock实现
性能
volatile总开销比锁低,只是写操作因为插入了许多内存屏障可能会慢一点,如果volatile能满足需求就用volatile