参考资料:
1、JDK1.8逐字逐句带你理解ConcurrentHashMap
https://blog.youkuaiyun.com/u012403290/article/details/67636469
2、Java并发编程总结4——ConcurrentHashMap在jdk1.8中的改进
https://www.cnblogs.com/everSeeker/p/5601861.html
3、jdk1.8中ConcurrentHashMap的实现原理
https://blog.youkuaiyun.com/fjse51/article/details/55260493
4、ConcurrentHashMap源码分析_JDK1.8版本
https://segmentfault.com/a/1190000009001468
5、多线程-ConcurrentHashMap(JDK1.8)
https://www.cnblogs.com/lujiango/p/7580558.html
ConcurrentHashMap
使用 segment (继承 ReentrantLock) 和 volatile 来保证线程安全性
segment 的数量为 16,每个 segment 中桶(HashEntry[])的数量可以增加,桶中放的是 由 HashEntry 组成的链表;count 表示 segment 中元素的数量, modCount 统计导致结构变化操作的次数(put、remove、replace、clear)
HashEntry 中的 value 变量 和 指向下一个节点的引用变量 next 都是使用 volatile 关键字进行修饰的,以此保证有序性和可见性
get() 方法不加锁,先找 segemnt 再找 桶
put() 方法要加锁,插入之前先判断 count 与阈值的关系,有需要的话则进行扩容处理(桶的容量扩容两倍)
put、remove、replace、clear 操作都要加锁
- size() 先尝试两次不加锁的统计各个 segment 中的 count,如果结果不一致,则采用对全部 segment 加锁的方式统计
JDK 1.8 中的 ConcurrentHashMap
使用 synchronized 和 volatile 关键字来保证线程安全
取消 segment ,当桶中 链表 长度大于 8 时,将链表转换为 RBTree
get()方法不加锁
put()方法:
如果桶是空的,则初始化桶,并采用 CAS 操作将元素放在链表的首位
如果桶非空,则通过使用 synchronized 锁住 链表的第一个节点(以此来锁住整个桶),再使用 Unsafe 类的 CAS 操作将元素放在链表的末尾
JDK 1。8 中 ConcurrentHashMap 中使用 synchronized 替代 Segment ,使得锁的粒度更加精细,以此提高程序的性能