ConcurrentHashMap源码刨析
ConcurrentHashMap相比于HashMap来讲,是线程安全的。底层的数据结构相同,都是数组+链表+红黑树。
Segment分段锁技术
因Segment继承ReentrantLock加锁,所以ConcurrentHashMap支持并发操作。
static class Segment<K,V> extends ReentrantLock implements Serializable {
private static final long serialVersionUID = 2249069246763182397L;
final float loadFactor;
Segment(float lf) { this.loadFactor = lf; }
}
线程安全
简单理解就是,ConcurrentHashMap 是一个 Segment 数组,Segment 通过继承ReentrantLock 来进行加锁,所以每次需要加锁的操作锁住的是一个 segment,这样只要保证每个 Segment 是线程安全的,也就实现了全局的线程安全。
并行度(默认 16)
![](https://updatecg.oss-cn-beijing.aliyuncs.com/ConcurrentHashMapJDK7.jpg)
![](https://updatecg.oss-cn-beijing.aliyuncs.com/ConcurrentHashMapJDK8.jpg)
并发
减小锁粒度
减小锁粒度是指缩小锁定对象的范围,从而减小锁冲突的可能性,从而提高系统的并发能力。减小锁粒度是一种削弱多线程锁竞争的有效手段,这种技术典型的应用是 ConcurrentHashMap(高性能的 HashMap)类的实现。对于 HashMap 而言,最重要的两个方法是get 与set 方法,如果我们对整个 HashMap 加锁,可以得到线程安全的对象,但是加锁粒度太大。Segment 的大小也被称为ConcurrentHashMap 的并发度。
分段锁
ConcurrentHashMap,它内部细分了若干个小的 HashMap,称之为段(Segment)。默认情况下一个ConcurrentHashMap 被进一步细分为 16 个段,既就是锁的并发度。
如果需要在 ConcurrentHashMap 中添加一个新的表项,并不是将整个 HashMap 加锁,而是首先根据hashcode 得到该表项应该存放在哪个段中,然后对该段加锁,并完成put 操作。在多线程环境中,如果多个线程同时进行put 操作,只要被加入的表项不存放在同一个段中,则线程间可以做到真正的并行。