作者热门文章
- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
谁能解释为什么这个例子在没有 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...
}
更多:我明白了,我们不关心这个值是否被计算了两次(所以它不是真正的线程安全的)。我还想知道在计算哈希码后创建的新线程是否保证能看到新的哈希码?
最佳答案
这是如履薄冰,但这是解释。可见性问题意味着某些线程可能会看到旧版本,而某些线程可能会看到新版本。在我们的例子中,一些线程看到 0
而其他线程 - cachedHashCode
。
调用hashCode()
并查看cachedHashCode
的线程将只返回它(if (h == 0)
条件不满足)一切正常。
但是看到 0
的线程(尽管 cachedHashCode
可能已经被计算过)将再次重新计算它。
换句话说,在最坏的情况下,每个线程都会进入第一次看到 0
的分支(就像它是 ThreadLocal
一样)。
由于 computeHashCode()
是幂等的(非常重要),多次调用它(通过不同的线程)并将它重新分配给同一个变量应该不会有任何副作用。
关于java - 没有volatile的线程安全,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9103449/
我是一名优秀的程序员,十分优秀!