如果我使用 32 位基元和函数幂等,为什么可以跳过 DCL 的任何同步?



我读过以下经典名文:"双重检查锁定已损坏"声明

我有一个关于以下方面的问题:

事实上,假设 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 开始,双重检查锁定是安全的。

计算哈希编码((真的只会被调用一次吗?

不。该方法不以任何方式同步。但是,它是线程安全的,因为它是幂等的。

最新更新