针对Java中单例模式懒汉模式里的volatile关键字的一个疑问

懒汉式比较常见的写法是:

public class Lazy {

    private static volatile Lazy instance;

    private Lazy(){}

    public static Lazy getInstance() {
        if (instance == null) {
            synchronized (Lazy.class) {
                if (instance == null) {
                    instance = new Lazy();
                }
            }
        }
        return instance;
    }
}

针对此处volatile的作用,大部分文章里提到的都是禁止指令重排序

但因为最近看了JMM,产生了一个疑问。

如果不加volatile,在多线程下同时调用getInstance()方法,那针对instance变量,是不是每个子线程都会先从主内存中读取到本地内存中,然后其中一个线程执行了instance = new Lazy();。此时即便指令重排序了,那也应该是全部执行完,才会从本地内存写会主内存吧。

如果考虑JMM中的本地内存和主内存的话,真的还需要加volatile吗?

阅读 2.7k
2 个回答

没有 volatile ,在线程读到 instance 不为 null 的时候,跟其它线程没有“同步”。这时,它虽然可以看到 instance 不是 null ,但是它“看到的” instance 可能并没有初始化结束。

volatile 提供“同步”语义。如果在一个线程里看到是先初始化结束,instance 再被赋值,那么再所有其它线程里看到的也是这个顺序。

不同线程“看到的”指令执行顺序可能是不一样,跟本地内存没有关系。


https://segmentfault.com/q/10...

虽然不是同一种语言,但是如果没有 volatile ,问题和这个一摸一样

即使加载到本地内存,不用volatile也无法保证“可见性”。有可能你加载到本地内存的就是“没有完全初始化化”的对象。

根据Java内存模型的happen before原则,对volatile字段的写入操作先于读操作,即使两个线程同时修改和获取volatile变量,get操作也能拿到最新的值,这是用volatile替换锁的经典应用场景。

可以看看这篇文章:

https://segmentfault.com/a/11...

推荐问题
宣传栏