- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
下面的代码(Java Concurrency in Practice list 16.3)显然不是线程安全的:
public class UnsafeLazyInitialization {
private static Resource resource;
public static Resource getInstance() {
if (resource == null)
resource = new Resource(); // unsafe publication
return resource;
}
}
然而,几页之后,在第 16.3 节中,他们指出:
UnsafeLazyInitialization
is actually safe ifResource
is immutable.
我不明白那句话:
Resource
是不可变的,那么任何观察 resource
变量的线程都将看到它为 null 或完全构造(感谢 Java 内存提供的对 final 字段的强大保证型号)resource
的两次读取可以重新排序(if
中的一次读取和 return 中的一次读取
)。所以线程可以在 if
条件中看到非空 resource
但返回空引用 (*)。我认为 UnsafeLazyInitialization.getInstance()
可以返回 null,即使 Resource
是不可变的。是这样吗?为什么(或为什么不是)?
(*) 为了更好地理解我关于重新排序的观点,this blog post杰里米·曼森 (Jeremy Manson) 是 JLS 第 17 章关于并发性的作者之一,他解释了如何通过良性数据竞争安全地发布 String 的哈希码,以及删除局部变量的使用如何导致哈希码错误地返回 0,因为可能的重新排序与我上面描述的非常相似:
What I've done here is to add an additional read: the second read of hash, before the return. As odd as it sounds, and as unlikely as it is to happen, the first read can return the correctly computed hash value, and the second read can return 0! This is allowed under the memory model because the model allows extensive reordering of operations. The second read can actually be moved, in your code, so that your processor does it before the first!
最佳答案
我认为你在这里的困惑是作者所说的安全出版的意思。他指的是非空资源的安全发布,但您似乎明白这一点。
您的问题很有趣 - 是否可以返回 null 缓存的资源值?
是的。
允许编译器像这样重新排序操作
public static Resource getInstance(){
Resource reordered = resource;
if(resource != null){
return reordered;
}
return (resource = new Resource());
}
这不违反顺序一致性规则,但可以返回空值。
这是否是最好的实现还有待商榷,但没有规则可以防止这种类型的重新排序。
关于java - 不变性和重新排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14624365/
我是一名优秀的程序员,十分优秀!