java double-check为啥要加volatile(是因为可见性还是有序性)?

通过百度:

  1. 我知道java volatile可以保证可见性和有序性。
  2. 我知道java单例实现:double-check模式需要加上volatile,

但是为什么需要加上volatile?百度好像有两种意见。

基于可见性的考虑,参考:https://www.bilibili.com/video/BV1gX4y1a7sH?p=11&vd_source=80...
作者的意思:没有加上volatile,不同的线程间的缓存副本无法可见,导致重复多次初始化。

基于有序性的考虑,参考:https://blog.csdn.net/qq_44842835/article/details/132166785
作者的意思:对象实例化可以简单分为三步:1、分配内存 2、初始化对象 3、将对象的引用赋值给instance。因为指令重排,顺序可以变成1->3->2,因此其他线程很可能获得一个未完全初始化的实例。

请问上述两种观点谁对谁错?能否能通过java代码来证明和实现?

阅读 889
avatarAI BotBETA

上述两种观点都有一定的正确性,但它们分别强调了volatile在解决并发问题时的不同方面。

  1. 可见性:在多线程环境中,如果一个线程的修改没有立即被其他线程看到,就可能导致数据的不一致。volatile关键字可以确保每个线程都看到共享变量的最新值。在你的例子中,如果没有volatile,不同的线程可能看不到已经初始化的对象,导致重复初始化。
  2. 有序性:在Java内存模型中,指令重排可能会导致一些意想不到的结果。例如,如果你的代码先分配内存,然后赋值给某个引用,由于指令重排,其他线程可能立即看到这个引用指向未初始化的内存地址。通过使用volatile,可以确保分配内存、初始化对象和设置引用的顺序不会被重排,从而防止其他线程看到未完全初始化的对象。

下面是一个简单的Java代码示例,用于证明volatile关键字对double-check单例模式的重要性:

public class Singleton {
    private static volatile Singleton instance;
    private Singleton() {}

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

在这个例子中,如果没有volatile关键字,两个线程可能会同时进入if (instance == null)的判断逻辑分支,并同时创建新的Singleton实例。使用volatile关键字可以确保只有一个线程能够进入同步块,并成功创建单例实例。

这个例子也说明了volatile关键字对于保证单例模式的有序性和可见性都是非常重要的。

1 个回答
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题