ConcurrentHashMap
如何保证线程安全
1.7 通过 Segement 可重入的分段锁
1.8 元素链表头节点 CAS 实现锁分离;volatile 修饰 table 和 sizeCtl 属性保证线程可见
重要属性
sizeCtl
默认为 0,用来控制 table 的初始化和扩容操作
-1 代表 table 正在初始化
-N 表示有 N-1 个线程正在进行扩容操作
如果 table 未初始化,表示 table 需要初始化的大小。
如果 table 初始化完成,表示 table 的容量,默认是 table 大小的 0.75 倍
扩容
扩容步骤
1、通过 CPU 核心数和数组长度计算每个线程负责迁移的桶个数,最小为 16。线程数量如何确定?
2、初始化 nextTable,将原 table 容量增加一倍。
3、将原 table 链表或者红黑树中的元素分为高位链和低位链,然后将链表移动到 n+1 位置上去。
4、最后一个扩容线程会负责重新检查一遍数组查看是否有遗漏的桶
扩容中并发读写的处理
1、对于 get 读操作,如果当前节点有数据,还没迁移完成,此时不影响读,能够正常进行。如果当前链表已经迁移完成,那么头节点会被设置成 fwd 节点,此时 get 线程会帮助扩容。
2、对于 put/remove 写操作,如果当前链表已经迁移完成,那么头节点会被设置成 fwd 节点,此时写线程会帮助扩容,如果扩容没有完成,当前链表的头节点会被锁住,所以写线程会被阻塞,直到扩容完成。
好文章
ConcurrentHashMap1.8 - 扩容详解 CSDN
ConcurrentHashMap 方法属性分析 掘金
待整理
1、扩容过程中的线程数变更和线程分配的桶如何变更
2、高位链低位链的生成和迁移过程
Simple is Awesome