线程安全无挥发 [英] thread safe without volatile
问题描述
任何人都可以解释为什么这个示例在没有volatile的情况下是线程安全的吗?
Can anyone explain why this example is thread safe without volatile?
http://www.cs.umd.edu/~ pugh/java/memoryModel/DoubleCheckedLocking.html
事实上,假设computeHashCode函数始终返回相同的结果并且没有副作用(即幂等),那么您甚至可以摆脱所有同步.
// Lazy initialization 32-bit primitives
// Thread-safe if computeHashCode is idempotent
class Foo {
private int cachedHashCode = 0;
public int hashCode() {
int h = cachedHashCode;
if (h == 0) {
h = computeHashCode();
cachedHashCode = h;
}
return h;
}
// other functions and members...
}
更多:我明白了,我们不在乎该值是否被计算两次(因此它不是真正的线程安全的).我还想知道在计算哈希码之后创建的新线程是否可以保证看到新的哈希码?
MORE: I get it, we don't care if the value is computed twice (so it is not truly thread safe). I also like to know if new threads created after the hashcode has been calculated is guaranteed to see the new hashcode?
推荐答案
这步履蹒跚,但这是解释.可见性问题意味着某些线程可能会看到旧版本,而某些线程可能会看到新版本.在我们的例子中,有些线程看到0
,而另一些线程看到cachedHashCode
.
This is walking on a thin ice, but here is the explanation. Visibility problem means that some threads might see old version and some - new one. In our case, some threads see 0
while others - cachedHashCode
.
调用hashCode()
并看到cachedHashCode
的线程将只返回它(不满足if (h == 0)
条件),并且一切正常.
Threads that call hashCode()
and see cachedHashCode
will just return it (if (h == 0)
condition is not met) and everything works.
但是看到0
的线程(尽管可能已经计算了cachedHashCode
)将再次重新计算它.
But threads that see 0
(despite the cachedHashCode
might have already been computed) will just recompute it again.
换句话说,在最坏的情况下,每个线程都会第一次进入分支并看到0
(就像它是ThreadLocal
一样).
In other words, in the worst case scenario, every thread will enter the branch seeing 0
for the first time (like if it was ThreadLocal
).
由于computeHashCode()
是幂等的(非常重要),因此多次调用它(通过不同的线程)并将其重新分配给同一变量应该没有任何副作用.
Since computeHashCode()
is idempotent (very important), both calling it several times (by different threads) and reassign it again to the same variable shouldn't have any side effects.
这篇关于线程安全无挥发的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!