2

我正在浏览ConcurrentHashMapjdk 7 中的源代码并且有几个问题。我已经在 StackOverFlow 上浏览了所有关于 CHM 的问题,但找不到答案。

  1. CHM 中的操作是否get()保证得到put()其他线程的正确值?我问这是因为 get 不是synchronized,除非它看到空值。null 值如何确保其他线程正在更新相同的记录,然后 get 与锁定一起使用?

  2. 这与HashEntry存储键和值的静态类有关。

    一个。为什么这门课是决赛?只是为了确保没有人继承它吗?如果有人继承它会发生什么——这有什么问题吗?

    湾。将下一个字段设为 final 如何有助于获得线程安全?

    C。为什么Key也是final?(我不确定为什么 Key 也是最终的HashMap

4

1 回答 1

6

是否保证 CHM 中的 get 操作能够获得其他线程的 put 正确值?

只要put()在调用get(). CHMvolatile在内部使用访问和其他锁​​来确保数据同步,不一定是synchronized关键字。

我问这是因为 get 不同步,除非它看到空值。null 值如何确保其他线程正在更新相同的记录,然后 get 与锁定一起使用?

我假设您指的是这个 javadoc:

因为 value 字段是 volatile 的,而不是 final 的,所以在 Java 内存模型中,非同步读取器在通过数据竞争读取时看到 null 而不是初始值是合法的。尽管导致这种情况的重新排序实际上不太可能发生,但 Segment.readValueUnderLock 方法用作备份,以防在未同步的访问方法中看到空(预初始化)值。

这是试图解释该值不是最终的,因此构造函数中的初始化可以重新排序,并且读者可以看到一个空值。我认为这就是不允许 CHM 存储空值的原因。这允许他们测试 null ,然后在一个synchronized块内执行另一个 get 。

有关重新排序的构造函数的更多信息,请参阅:实例初始化的重新排序和分配给共享变量的可能吗?

为什么HashEntry课程是决赛?只是为了确保没有人继承它吗?

是的。这确保了类不能被子类化。这确保了不变性。如果有人对其进行子类化,他们可以更改字段的可见性并破坏并发合同。

使 next [[field]] final 如何有助于获得线程安全?

next字段(以及keyandhash字段)是final因为这确保了该字段在构造函数中完全初始化。这确实提高了线程安全性,因为优化器无法在构造函数结束后重新排序初始化,并且保证所有线程都能看到数据。

有关该value字段的信息以及它们如何防止它不被允许覆盖,请参见上文。finalput(...)

为什么Key也是final?(我不确定为什么 Key 在 HashMap 中也是最终的)

与 相同的答案HashEntry

于 2013-08-30T20:20:59.353 回答