java 多线程:volatile 详解

发布时间 2023-05-24 16:48:45作者: 黄光跃

可以保证多线程的 可见性、有序性,不能保证原子性

为什么不能保证原子性

每个单独的读写操作都会及时刷新到主存中,后续操作如果失败,没有什么回滚机制(感觉理所当然,但是现在行业卷,面试时就要问你zzz)

怎么保证可见性的

内存屏障保证的。什么是内存屏障?就是一条特殊的 cpu 指令,lock 前缀指令。
当线程 A 对 volatile 变量执行了写操作,会发一条 lock 前缀指令把工作内存的值刷到主存中,保证当前线程与主存中的值一致
当线程 B 对 volatile 变量执行读操作时也会发送一条 lock 前缀指令获取主存的最新值吗?肯定不是的,不然直接 volatile 变量每次都操作主存得了;还有就是如果别的线程不更改值呢,不就可以一直使用当前线程缓存的值吗。原因是:缓存一致性协议(MESI),线程A刷新了主存,线程B就知道当前缓存值过期了,这时才去读主存的值

怎么保证有序性的

也是内存屏障保证的。和 lock 类似,lock 前缀指令就会刷新主存,编译器会在适当的位置会插入内存屏障指令来禁止重排序

volatile 应用场景

  • AQS(volatile+cas保证线程安全)
  • 双重检查(double-checked)
class Singleton {
    private volatile static Singleton instance;
    private Singleton() {
    }
    public static Singleton getInstance() {
        if (instance == null) {
            syschronized(Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    } 
}