5

java.util.concurrent.ConcurrentHashMap使用Segment数组作为Mutex并且Segment Object比缓存线小。

这会导致虚假分享吗?

4

2 回答 2

4

首先,最好区分ConcurrentHashMapJava 7 和ConcurrentHashMapJava 8,因为实现差异很大。

ConcurrentHashMap在 Java 7 中

Peter Lawrey 是正确的,Segment类 extendsReentrantLock聚合了AbstractQueueSynchronizer. 就其本身而言,AbstractQueuedSynchronizer包含足够的long字段来填充缓存行的通常填充长度(64 字节)。如果您进行数学计算,可能会发现Segment实际上需要 1 个缓存行 + 一点点,因此您可能会争辩说它容易受到错误共享的影响。 Java Object LayoutIntel VTune应该能够帮助您解决这个问题。

ConcurrentHashMap在 Java 8 中

在 Java 8 中,ConcurrentHashMap不再依赖条带锁定。相反,它使用了一种大部分无锁算法,该算法适用于存储桶的粒度级别(Node在新实现中调用),而不是一组存储桶(Segment在旧实现中调用)。如果您深入研究实现细节,您会注意到:

  1. 新的实现不太容易受到错误共享的影响,因为您希望不同的线程Node只有在桶冲突时才会命中相同的线程。
  2. @Contended注解用于 Java 8 的内部实现ConcurrentHashMap,因此 Doug Lea 和其他研究它的人确实一直在考虑虚假共享。它恰好用于您期望虚假共享最严重的地方 - 当您尝试跟踪表格的大小时。
于 2016-03-23T12:07:13.170 回答
2

虽然段很小,但这不是多线程支持发生的地方。它扩展了 ReentrantLock,它使用了一个 Sync 对象,该对象扩展了 AbstractQueuedSchronizer,它使用了 Node 对象。所有这些对象都将作为一个组进行复制,并且可能会被合理地隔开。这将取决于 GC 的实现如何完成,但对于 Hotspot,它是以发现的相反顺序复制的(即深拷贝),所以这可能会很好。

于 2016-03-23T08:21:48.107 回答