知识卡片
CHM分段到桶锁
内容
这是版本演进史,不是唯一实现:JDK 1.7 把哈希表拆成多个 Segment(继承 ReentrantLock),put 只锁 key 所在 Segment,粒度是”段级”。JDK 1.8 去掉分段,改在每个桶上做 CAS(无竞争)或 synchronized(有竞争),粒度缩到”桶级”。复合更新应优先用 compute/merge 而非 get-then-put。
参考来源
- 位置:《Java高并发核心编程.卷2,多线程、锁、JMM、JUC、高并发设计模式》第7章《JUC容器类》7.5.3节《JDK 1.7版本ConcurrentHashMap的核心原理》、7.5.5节《JDK 1.8版本ConcurrentHashMap的核心原理》(源文件:_epub-src/OEBPS/Text/chapter252.xhtml、chapter254.xhtml)
- 结论依据:原文给出JDK 1.7版本Segment继承ReentrantLock、put只锁对应Segment的源码,以及JDK 1.8版本改用Node数组+链表/红黑树、通过CAS和synchronized在桶级别加锁、链表长度超过8且数组容量≥64时树化的具体实现,因此推出本卡关于版本演进和锁粒度变化的结论。
- 原始内容:static final class Segment<K,V> extends ReentrantLock implements Serializable……若并发级别为16,table则守护ConcurrentHashMap包含的桶总数的1/16……JDK 1.8版本的ConcurrentHashMap中通过一个Node<K,V>[]数组table来保存添加到哈希表中的桶,而在同一个Bucket位置是通过链表和红黑树的形式来保存的……当在同一个位置的个数达到了8个以上,如果数组的长度还小于64,就会扩容数组。如果数组的长度大于等于64,就会将该节点的链表转换成树。