为什么Java双重检查锁单例必须使用volatile关键字?

问题描述 投票:0回答:1

我也看到过类似的问题,但我仍然有些困惑。寒冷在这里:

private volatile static DoubleCheckSingleton instance;

private DoubleCheckSingleton() {}
public static DoubleCheckSingleton getInstance(){

    if(instance==null){ //first

        synchronized (DoubleCheckSingleton.class){

            if(instance==null){  // second
                instance=new DoubleCheckSingleton();
            }

        }

    }

    return instance;

}

在此问题Why is volatile used in double checked locking中,它说,没有volatile关键字,线程可能在构造函数完成之前分配实例变量,因此另一个线程可能会看到一半构造的对象,这可能会导致严重的问题。

但是我不知道波动如何解决问题。易失性用于确保可见性,因此,当线程A将半结构化对象分配给实例变量时,另一个线程可以立即看到更改,这使情况变得更糟。

挥发物如何解决问题,请有人向我解释。谢谢!

java concurrency volatile
1个回答
0
投票

线程可以在构造函数完成之前分配实例变量

实际并非如此。在代码示例中,赋值就在那里:

instance=new DoubleCheckSingleton()

显然,执行该分配的线程可能无法在返回构造函数调用之前进行分配。

问题是,当两个不同的线程在两个不同的处理器上运行而没有任何同步时,它们不一定会同意分配发生的顺序。因此,即使线程A分配了新对象的字段(在new DoubleCheckSingleton()调用之内)之前,它也分配了instance,线程B仍可能会无序看到这些分配。线程B在看到instance所做的其他一些事情之前,可能已经看到new DobuleCheckSingleton()的分配。

instance声明为volatile会同步线程。 volatile保证everything线程A所做的之前当线程B获取volatile变量的值时,线程B会为它分配一个volatile变量。

© www.soinside.com 2019 - 2024. All rights reserved.