我读过以下经典名文:"双重检查锁定已损坏"声明
我有一个关于以下方面的问题:
事实上,假设 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...
}
这篇文章是为java 4编写的。它对java 8+仍然有效吗?
computeHashCode()
真的只会被调用一次吗?
不,它可以多次执行。同步将更改"刷新"到其他线程,如果没有它,理论上在一个线程中所做的更改将永远无法在该线程之外进行通信。
但是,文章并没有说computeHashCode
只会被调用一次,只是竞争条件不会引起任何问题。int
写入保证是原子的,如果computeHashCode
是幂等的(这要求类及其字段实际上是最终的(,你只会用相同的值覆盖以前的值,所以不会发生任何坏事。
不,它不能保证只调用一次,但这无关紧要。
如果computeHashCode
是幂等的,则调用它额外的时间不起作用,因此线程不能相互干扰。
来自您发布的同一篇文章:
JDK5 及更高版本扩展了易失性的语义,以便系统能够 不允许对易失性的写入进行重新排序 任何以前的读取或写入,以及易失性的读取不能 针对任何后续读取或写入重新排序。
通过此更改,可以使双重检查锁定习惯用法起作用 通过将帮助程序字段声明为易失性。这在以下情况下不起作用 JDK4 及更早版本。
这意味着从 Java 5 开始,双重检查锁定是安全的。
计算哈希编码((真的只会被调用一次吗?
不。该方法不以任何方式同步。但是,它是线程安全的,因为它是幂等的。