详细的解释 ↓
漫画:什么是ConcurrentHashMap?
Java泛型底层源码解析--ConcurrentHashMap(JDK1.7)
并发读写缓存实现机制(二):高并发下数据写入与过期
深入理解Java内存模型(六)——final
- HashTable和Collections.synchronizedMap(new HashMap()) 能提供线程安全的hashmap,但是都只是用sychronized锁住整个hash表,所有线程进行读写时都需要去竞争同一把锁,效率很低。
- ConcurrentHashMap使用了锁分段技术,降低了锁的粒度。将一张表分割成多个部分,用段Segment数组表示这些部分,每个segment 都有一个锁,互不影响。多个操作发生在不同的段上时,可以并发进行。
- 采用二次hash,第一次将key映射到segment数组的index,第二次映射到segment的hashEntry数组的index。
- concurrencyLevel 并发度,默认16。即segment的数量,不可改变所以扩容时只需扩容需要扩的segment。
- HashEntry的next是final的,所以remove时需要复制一遍其他的链表元素,put时是头插。为什么用final?因为读写是并发的,用final确保读时该结点后的结点都是不变的。顶多是读到的数据过期而不是错误
- put 可重入锁,确保线程不会把自己锁住。
-
size方法。值不一定准确
segment有count 记录元素数量,被volatile修饰;modCount 记录增删元素操作的数量
累加segment的count时用乐观锁,两次累加count和modCount,如果第一次和第二次的modCount总数相等,说明累加过程没有增删过元素(还是有可能的比如一增一删),count总数就是size,如果不同就再进行一次计算,在不同就锁住所有的segment。 - key或value为null抛异常
final V putVal(K key, V value, boolean onlyIfAbsent) {
if (key == null || value == null) throw new NullPointerException();