volatile在java中的单例双空检查实现中的使用
我想知道在Singleton的双空检查实现中将实例变量设置为volatile有什么用。因为根据我的理解,同步块提供之前是隐式发生的。没有两个线程可以同时访问该同步块,并且在退出同步块时,线程会将其所有本地缓存数据写入主内存。 我搜索了很多,但仍然对这个实现有疑问。请解释正确的用法volatile在java中的单例双空检查实现中的使用,java,multithreading,singleton,volatile,Java,Multithreading,Singleton,Volatile,我想知道在Singleton的双空检查实现中将实例变量设置为volatile有什么用。因为根据我的理解,同步块提供之前是隐式发生的。没有两个线程可以同时访问该同步块,并且在退出同步块时,线程会将其所有本地缓存数据写入主内存。 我搜索了很多,但仍然对这个实现有疑问。请解释正确的用法 private volatile Singleton INSTANCE; public Singleton get() { if (INSTANCE == null) { synchron
private volatile Singleton INSTANCE;
public Singleton get() {
if (INSTANCE == null) {
synchronized (this) {
if (INSTANCE == null) {
INSTANCE = new Singleton();
}
}
}
return INSTANCE;
}
在上面的双重检查代码中。如果我不让我的实例变得易变,那么会有什么问题呢。因为当第一个线程进入同步块时,其他线程将无法访问该块。当第一条线离开那个块时。对象将被创建,并且由于发生在属性之前,实例的最新值将写入主内存。那么为什么volatile在这种情况下很重要呢
这里有一个类似问题的链接()。但答案并不十分清楚。
我不认为在上面给定的场景中,任何类型的JVM优化都会导致在同步块之前发生的中断
因为根据我的理解,同步块提供之前是隐式发生的。没有两个线程可以在退出同步块时同时访问该同步块
如果您有一个简单的惰性单例实现,这是正确的。在这种情况下,对变量的每次访问都要经过syncronized块
private Singleton INSTANCE;
public static synchronized Singleton getInstance() {
if (INSTANCE == null) {
INSTANCE = new Singleton();
}
return INSTANCE;
}
但一旦您有了一个安全的双重检查延迟实现,并不是每个代码路径都经过同步块。对该方法的第二次调用将从本地字段读取变量,而无需输入synchronized
块,实例必须是可变的
private volatile Singleton INSTANCE;
public Singleton get() {
if (INSTANCE == null) {
synchronized (this) {
if (INSTANCE == null) {
INSTANCE = new Singleton();
}
}
}
return INSTANCE;
}
您可以在中阅读有关安全发布的更多信息 volatile在这里很重要,因为JVM的内部是字节码级别的。声明
INSTANCE = new Singleton()
在字节码级别实际上是这样的:
1. INSTANCE = create Singleton object
2. call constructor of INSTANCE
如果实例是易变的,JVM保证从其他线程的角度来看,1+2是作为原子操作执行的,例如,在将实例存储到字段之前,先将其存储在堆栈上。如果它不是volatile,则可能是在调用构造函数之前,其他线程已经可以看到对Singleton的引用。因此,这些线程可能会看到一个不完整的对象。向我们展示您正在谈论的代码,并准确地向我们展示在您谈论之前发生的事情。然后我们可以解释它。(这可能是一个副本,尽管没有更多细节,很难选择最佳的dup。)请将其放入问题中。这是一个副本,感谢您澄清volatile仅用于双重检查锁定单例模式,并给出正确的原因“实例变量的第一次检查是在不进入同步块的情况下检查null”。