-
ConcurrentHashMap(以下称为CHM)各版本
-
JDK 5:分段锁,必要时加锁。
通过Segment来分段,减少每次操作map时都需要执行同步操作而必须阻塞从而无法继续执行的可能。
-
JDK 6:优化二次Hash算法。
JDK 5中小整数的Hash高位不均匀分布,始终为高位15,JDK 6经优化后高低位保持均匀分布。
-
JDK 7 :Segment懒加载,volatile和cas。
JDK 7 之前Segment随CHM初始化 ,JDK 7 实现了懒加载,使用时再初始化,又由于多线程时其他线程可能访问不到刚初始化的Segment,故在JDK7大量使用volatile。
-
JDK 8 :放弃Segment,基于HashMap原理的并发实现。
内部直接访问table[],针对table[]里对应的Node加锁,新来的元素会放置于此Node后面。
-
-
CHM计数
- JDK 5~7:基于Segment元素个数求和,二次不同就加锁再求一次。
- JDK 8:引入CounterCell,本质上也是分段计数。
-
CHM是弱一致性
- 添加元素后不一定马上能读到。
- 清空后可能仍然有元素。
- 遍历之前的段元素变化会读到。
- 遍历后的段元素变化读不到。
- 遍历时元素变化不抛异常。
-
CHM与HashTable对比
锁类型 CHM HashTable 大锁 对HashTable对象加锁 小锁 JDK 5~7:分段锁,JDK 8:节点锁 长锁 直接对方法加锁 短锁 先尝试获取,失败再加锁 读写锁共用 只有一把锁,从头锁到尾 读写锁分离 JDK 5~7:读失败再加锁,JDK 8:voltile读,CAS写 -
锁优化总结
- 长锁不如短锁:尽可能只锁必要部分。
- 大锁不如小锁:尽可能拆分加锁对象。
- 公锁不如私锁:尽可能私有锁内逻辑。
- 嵌套不如扁平:尽可能避免锁锁嵌套。
- 分离读和写锁:尽可能分离读和写锁。
- 粗化高频次锁:尽可能合并高频小锁。
- 消除无用废锁:尽可能用volatile替代。
网友评论