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

时间:2019-09-19 14:39:23

标签: java multithreading concurrency primitive idempotent

我已阅读以下经典著名文章:The "Double-Checked Locking is Broken" Declaration

我有一个问题:

  

事实上,假设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()只会被调用一次吗?

3 个答案:

答案 0 :(得分:4)

否,它可以多次执行。同步“使”更改“散布”到其他线程,如果没有它,则从理论上讲,一个线程中所做的更改永远无法在该线程外进行通信。

但是,本文并没有说computeHashCode会被精确地调用一次,只是竞争条件不会引起任何问题。 int的写保证是原子的,并且如果computeHashCode是幂等的(这要求类及其字段有效地是最终的),则只需用相同的值覆盖以前的值,所以没什么不好的发生。

答案 1 :(得分:1)

不,它不能保证只能被调用一次,但这无关紧要。

如果computeHashCode是幂等的,则额外调用它是无效的,因此线程不会相互干扰。

答案 2 :(得分:1)

与您发表的同一篇文章

  

JDK5和更高版本扩展了volatile的语义,从而使系统   不允许对volatile的写入进行重新排序   以前的任何读或写操作,以及对volatile的读操作都不能   关于以下任何读或写重新排序。

     

通过此更改,可以使Double-Checked Locking惯用语生效   通过声明helper字段是可变的。这在以下情况下不起作用   JDK4和更早版本。

这意味着从Java 5开始,双重检查锁定是安全的。

  

computeHashCode()是否只会被调用一次是真的吗?

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