Java 使用本地变量的单例安全发布
在阅读这篇文章时,我遇到了下面解释安全发布字段的代码Java 使用本地变量的单例安全发布,java,multithreading,Java,Multithreading,在阅读这篇文章时,我遇到了下面解释安全发布字段的代码 public class SafeLocalDCLFactory implements Factory { private volatile Singleton instance; @Override public Singleton getInstance() { Singleton res = instance; if (res == null) { synchronized (this) {
public class SafeLocalDCLFactory implements Factory {
private volatile Singleton instance;
@Override
public Singleton getInstance() {
Singleton res = instance;
if (res == null) {
synchronized (this) {
res = instance;
if (res == null) {
res = new Singleton();
instance = res;
}
}
}
return res;
}
}
我的疑问是为什么我们需要在getInstance()
中定义的本地varres
?易失性
和DCL
是否足以保证安全发布
?在此处定义本地varres
,然后将其与null
进行比较的目的到底是什么
编辑:本文解释了下面的内容,以证明使用本地var的必要性。但是我们如何保护自己不返回null呢
在这里引入局部变量是一个正确性修正,但仅限于
部分:在发布
Singleton实例,并读取其任何字段。我们只是
保护自己不返回“null”而不是Singleton
实例
它最小化了从易失性变量
实例
读取的次数。易失性变量访问比非易失性内存访问更昂贵,因为它通常涉及内存屏障。通过将其分配给临时变量,如果volatile变量已经初始化,则此代码只读取一次,而不是两次(一次检查,一次返回)。F-Up问题:因为只有创建实例的null检查中的代码是同步的,instance
是否可能在空检查和创建实例之间进行更改?场景:空检查为正;换线;空检查阳性;执行同步块并创建和保存isntance;换线;再次执行同步块并覆盖现有实例一旦一个线程进入同步块,另一个线程就无法进入。当初始化线程完成时,等待的线程将再次检查并查看实例是否已初始化。@JohannesH。在第二次线程更改中,它不会再次检查同步块内的空值吗?因为已经由第一个线程创建,所以它将为false?I。。。错过了第二张支票。是的,你们是对的。@BurakSerdar,谢谢,但在文章中提到使用本地变量的真正原因如下:“在这里引入局部变量是一个正确性修正,但只是部分修正:在发布Singleton实例和读取其任何字段之间仍然没有发生任何变化。我们只是保护自己不返回“null”,而不是单例实例?