gpt4 book ai didi

Java多线程纠错——线程安全单例

转载 作者:搜寻专家 更新时间:2023-11-01 03:06:54 26 4
gpt4 key购买 nike

首先:是的,我知道在 Java 中实现单例的最佳方式通常是使用 enum,但是如果出于某种原因您需要子类化一个单例类,您不能使用枚举,所以...

JavaWorld 的 David Geary 很久以前发表了一篇关于在 Java 中实现单例的文章。他认为以下对线程安全单例实现的优化是有问题的:

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

(查看更多信息:http://www.javaworld.com/javaworld/jw-04-2003/jw-0425-designpatterns.html?page=4#sthash.G8lzWOfT.dpuf)

Geary 说这种“双重检查锁定”优化

is not guaranteed to work because the compiler is free to assign a value to the singleton member variable before the singleton's constructor is called. If that happens, Thread 1 can be preempted after the singleton reference has been assigned, but before the singleton is initialized, so Thread 2 can return a reference to an uninitialized singleton instance.

我的问题:以下更改能否解决该问题?我已经开始阅读 Goetz 的 Java 并发书,似乎允许编译器对线程内操作进行洗牌,所以我不太有信心......不过,在我看来 singleton = temp; 是一个原子操作,在这种情况下我认为它应该。请解释。

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

最佳答案

第二段代码与第一段代码顺序一致(在单线程环境下它们是严格等价的)并且没有引入任何额外的内存同步点。

是的,编译器有权重写第二个代码并将其转换为第一个代码,这意味着它也是不安全的。

singleton = temp; 是原子的这一事实在这里无济于事。它仅表示 singleton 为 null 或持有与 temp 相同的引用。但这并不排除 temp/singleton 指向“非构造”对象。

Java 内存模型按照事前发生 (HB) 关系工作。在这两个代码中只有一个 hb:同步块(synchronized block)的导出 hb 随后进入该 block 。 if (singleton == null) 不与 singleton=... 共享任何 hb 关系,因此可以发生重新排序。

最重要的是,解决它的唯一方法是在两个语句之间引入一个 hb:例如,通过将 if 移到同步块(synchronized block)中或通过将单例标记为 volatile。

关于Java多线程纠错——线程安全单例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19263749/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com