volatile

文章目录
  1. 1. volatile 的理解
    1. 1.1. 保证可见性
    2. 1.2. 不保证原子性
    3. 1.3. 禁止指令重排
  2. 2. volatile使用场景

volatile 的理解

volatile 是 Java 虚拟机提供的轻量级的同步机制

保证可见性

各个线程对主内存中共享变量的操作都是各个线程各自拷贝到自己的工作内存进行操作后再写回主内存中的。

这就可能存在一个线程 A 修改了共享变量 X 的值但还未写回主内存时,另一个线程 B 又对准内存中同一个共享变量 X 进行操作,但此时 A 线程工作内存中共享变量 X 对线程 B 来说并不是可见,这种工作内存与主内存同步存在延迟现象就造成了可见性问题。

不保证原子性

禁止指令重排

volatile 实现禁止指令重排优化,从而避免多线程环境下程序出现乱序执行的现象。

先了解一个概念,内存屏障又称内存栅栏,是一个CPU指令,它的作用有两个:
一是保证特定操作的执行顺序
二是保证某些变量的内存可见性(利用该特性实现volatile的内存可见性)

由于编译器和处理器都能执行指令重排优化。如果在指令间插入一条 Memory Barrier 则告诉编译器和 CPU,不管什么指令都不能和这条 Memory Barrier 指令重新排序,也就是说通过插入内存屏障禁止在内存屏障前后的指令执行重排序优化。内存屏障另外一个作用是强制刷出各种CPU的缓存数据,因此任何CPU上的线程都能读取到这些数据的最新版本。

volatile使用场景

单例模式 DCL 代码
单例模式 volatile 分析

DCL(双端检锁)机制不一定线程安全,原因是有指令重排序的存在,加入 volatile 可以禁止指令重排。
原因在于某一个线程执行到第一个检测,读取到的 instance 不为 null 时,instance 的引用对象可能没有完成初始化。
指令重排只会保证串行语义的执行一致性(单线程),但并不会关心多线程间的语义一致性。
所以当一条线程访问 instance 不为 null 时,由于 instance 实例未必已初始化完成,也就造成了线程安全问题。