1、ConcurrentHashMap结构图:
2、ConcurrentHashMap类图
1、HashEntry类
//ConcurrentHasHap存储最小单元 static final class HashEntry<K,V> { //key-value中的key值,是不可变的 final K key; //key通过hash算法生成的hash值,是不可变的 final int hash; //key-value的value值,value是可变的,但是保持可见性。 volatile V value; //HashEntry的下一个节点 final HashEntry<K,V> next; HashEntry(K key, int hash, HashEntry<K,V> next, V value) { this.key = key; this.hash = hash; this.next = next; this.value = value; } //返回一个HashEntry数组 static final <K,V> HashEntry<K,V>[] newArray(int i) { return new HashEntry[i]; } }
2、Segment内部类
该类继承于ReentrantLock类,实现序列化接口。对每个HashEntry修改在整个
table上加锁(也就是在segment上进行加锁)。
static final class Segment<K,V> extends ReentrantLock implements Serializablesegment字段:
该segment段内拥有的HashEntry数量。
transient volatile int count;table被修改的次数计数器(segment中,put,remove方法会修改该值)。读该segment内table的size, 如果获取size前和获取size后的modCount不同,则说明有另外线程修改了segment的table,获取的改size的snapshot不正确,size计算具体见size方法
transient int modCount;超过threshold,就会进行rehash
transient int threshold;每个segment存的HasnEntry的数组
transient volatile HashEntry<K,V>[] table;负载因子,threshold = Table.length * loadFactor;
final float loadFactor;
方法:
1、返回table数据中的hashEntry
HashEntry<K,V> getFirst(int hash) { HashEntry<K,V>[] tab = table; return tab[hash & (tab.length - 1)];//2的倍数求余 }2、 整个table加锁返回指定HashEntry的value值
V readValueUnderLock(HashEntry<K,V> e) { lock(); try { return e.value; } finally { unlock(); } }3、 根据key和hash值,获取相应value,读的时候并未加锁
V get(Object key, int hash) { //判断table中的HashEntry数量是否为0,注意count是可见的(volatile ) if (count != 0) { // read-volatile //根据hash获取table中数组中的HashEntry HashEntry<K,V> e = getFirst(hash); while (e != null) { //hash冲突,hash值和key值都相同,则可定位该HashEntry是key相对应的HashEntry。 if (e.hash == hash && key.equals(e.key)) { V v = e.value; if (v != null) return v; //value为空,则在锁状态下继续读一次 return readValueUnderLock(e); // recheck } //hash冲突,链表向下移动指针 e = e.next; } } return null; }4、判断是否包含该value,读的时候并未加锁
boolean containsValue(Object value) { if (count != 0) { // read-volatile HashEntry<K,V>[] tab = table; int len = tab.length; //遍历table中的每一个值 for (int i = 0 ; i < len; i++) { //遍历链表中的每一个值 for (HashEntry<K,V> e = tab[i]; e != null; e = e.next) { V v = e.value; //value为null的话,进行double check if (v == null) // recheck v = readValueUnderLock(e); if (value.equals(v)) return true; } } } return false; }replace相应HashEntry的value,修改要加锁,注意,这里try-finally语句,unlock写在finally中
boolean replace(K key, int hash, V oldValue, V newValue) { lock(); try { //找到key和hash值都相同的HashEntry HashEntry<K,V> e = getFirst(hash); while (e != null && (e.hash != hash || !key.equals(e.key))) e = e.next; boolean replaced = false; //找到相应的HashEntry,如果值与旧值相同,value修改为新的值 if (e != null && oldValue.equals(e.value)) { replaced = true; e.value = newValue; } return replaced; } finally { unlock(); } }put方法,奇怪的是不会HashEntry链表中增加
V put(K key, int hash, V value, boolean onlyIfAbsent) { lock(); try { int c = count; //当前count超过threshold,则进行rehash if (c++ > threshold) // ensure capacity rehash(); //获取table数组中的HashEntry HashEntry<K,V>[] tab = table; int index = hash & (tab.length - 1); HashEntry<K,V> first = tab[index]; HashEntry<K,V> e = first; //移动到相应的位置 while (e != null && (e.hash != hash || !key.equals(e.key))) e = e.next; V oldValue; if (e != null) { //有key值一样的hashEntry,保存旧的value值并返回,覆盖旧的value oldValue = e.value; if (!onlyIfAbsent) e.value = value; } else { //key匹配到的HashEntry为空,新建HashEntry,并存入table中 oldValue = null; ++modCount;//增加HashEntry节点,修改modCount的值 tab[index] = new HashEntry<K,V>(key, hash, first, value) count = c; // write-volatile } return oldValue; } finally { unlock(); } }rehash方法
void rehash() { //rehash后的长度不可以大于MAXIMUM_CAPACITY HashEntry<K,V>[] oldTable = table; int oldCapacity = oldTable.length; if (oldCapacity >= MAXIMUM_CAPACITY) return; //新的table是之前的两倍大 HashEntry<K,V>[] newTable = HashEntry.newArray(oldCapacity<<1); threshold = (int)(newTable.length * loadFactor); int sizeMask = newTable.length - 1; //对于table数组中不为null的HashEntry进行rehash for (int i = 0; i < oldCapacity ; i++) { // We need to guarantee that any existing reads of old Map can // proceed. So we cannot yet null out each bin. HashEntry<K,V> e = oldTable[i]; if (e != null) { //重新计算table数组中HashEntry节点的hash值。 HashEntry<K,V> next = e.next; int idx = e.hash & sizeMask; //如果该节点是单一节点,则修改节点在hashtable中位置 // Single node on list if (next == null) newTable[idx] = e; else { //该节点不是单一节点,next不为null,则找到lastRun的位置(链中可进行rehash的最后一个HashEntry) // Reuse trailing consecutive sequence at same slot HashEntry<K,V> lastRun = e; int lastIdx = idx; for (HashEntry<K,V> last = next; last != null; last = last.next) { int k = last.hash & sizeMask; if (k != lastIdx) { lastIdx = k; lastRun = last; } } newTable[lastIdx] = lastRun; //复制链中的可进行rehash的HashEntry到新的HashTable中 // Clone all remaining nodes for (HashEntry<K,V> p = e; p != lastRun; p = p.next) { int k = p.hash & sizeMask; HashEntry<K,V> n = newTable[k]; newTable[k] = new HashEntry<K,V>(p.key, p.hash, n, p.value); } } } } table = newTable; }移除节点
V remove(Object key, int hash, Object value) { lock(); try { int c = count - 1; //寻找要移除的节点e HashEntry<K,V>[] tab = table; int index = hash & (tab.length - 1); HashEntry<K,V> first = tab[index]; HashEntry<K,V> e = first; while (e != null && (e.hash != hash || !key.equals(e.key))) e = e.next; V oldValue = null; if (e != null) { V v = e.value; //如果e的值为null或者与希望移除value值一样 if (value == null || value.equals(v)) { oldValue = v; // All entries following removed node can stay // in list, but all preceding ones need to be // cloned. ++modCount; //记录e后面那一个节点 HashEntry<K,V> newFirst = e.next; //e节点前面的节点进行重新创建(为什么???),最后节点指向e的后面节点 for (HashEntry<K,V> p = first; p != e; p = p.next) newFirst = new HashEntry<K,V>(p.key, p.hash, newFirst, p.value); tab[index] = newFirst; count = c; // write-volatile } } return oldValue; } finally { unlock(); } }ConcurrentHashMap方法
public ConcurrentHashMap(int initialCapacity, float loadFactor, int concurrencyLevel) { //判断非法参数 if (!(loadFactor > 0) || initialCapacity < 0 || concurrencyLevel <= 0) throw new IllegalArgumentException(); if (concurrencyLevel > MAX_SEGMENTS) concurrencyLevel = MAX_SEGMENTS; //sshift用于统计,共进行了多少次2倍数的扩大 //segment size大小 // Find power-of-two sizes best matching arguments int sshift = 0; int ssize = 1; while (ssize < concurrencyLevel) { ++sshift; ssize <<= 1; } //segment大小没有用到的高位,据说用来计算用到的segment?? segmentShift = 32 - sshift; //segment的大小 segmentMask = ssize - 1; //创建segment数据 this.segments = Segment.newArray(ssize); if (initialCapacity > MAXIMUM_CAPACITY) initialCapacity = MAXIMUM_CAPACITY; //segment中,每个hashmap值的大小,先算出c,每个容器该有的大小,然后算出一个小于c的二的整数倍cap,做为每个hashmap大小 int c = initialCapacity / ssize; if (c * ssize < initialCapacity) ++c; int cap = 1; while (cap < c) cap <<= 1; //为每个segment创建hashmap for (int i = 0; i < this.segments.length; ++i) this.segments[i] = new Segment<K,V>(cap, loadFactor); }size()方法
public int size() { final Segment<K,V>[] segments = this.segments; //size大小 long sum = 0; long check = 0; //每个segment的modCount int[] mc = new int[segments.length]; //尝试两次计算size大小,RETRIES_BEFORE_LOCK为2 for (int k = 0; k < RETRIES_BEFORE_LOCK; ++k) { //第二次统计size大小 check = 0; //第一次统计size大小 sum = 0; int mcsum = 0; for (int i = 0; i < segments.length; ++i) { //计算size大小 sum += segments[i].count; //计算每个segment的modcount和 mcsum += mc[i] = segments[i].modCount; } //如果mcsum为0,说明ConcurrentHashMap为空 if (mcsum != 0) { for (int i = 0; i < segments.length; ++i) { //再次计算size大小 check += segments[i].count; //对比modCount是否有对ConcurrentHashMap修改,如果有,跳出循环,强制重试 if (mc[i] != segments[i].modCount) { check = -1; // force retry break; } } } //如果两次统计大小一样,则跳出循环 if (check == sum) break; } //如果两次统计都不成功,则每个segment上面加锁,进行size计算 if (check != sum) { // Resort to locking all segments sum = 0; for (int i = 0; i < segments.length; ++i) segments[i].lock(); for (int i = 0; i < segments.length; ++i) sum += segments[i].count; for (int i = 0; i < segments.length; ++i) segments[i].unlock(); } if (sum > Integer.MAX_VALUE) return Integer.MAX_VALUE; else return (int)sum; }根据key获取value,put,remove等方法类似,都是调用Segment中相应方法。
public V get(Object key) { //计算key的hash值 int hash = hash(key.hashCode()); //首先,根据hash值获取指定segment,然后再该segment中获取value的值,获取不到放回null return segmentFor(hash).get(key, hash); }遍历所有的segment,判断是否包含某一个值
public boolean containsValue(Object value) { if (value == null) throw new NullPointerException(); final Segment<K,V>[] segments = this.segments; int[] mc = new int[segments.length]; // Try a few times without locking for (int k = 0; k < RETRIES_BEFORE_LOCK; ++k) { int sum = 0; int mcsum = 0; //遍历所有的segment,如果包含该value,则返回true for (int i = 0; i < segments.length; ++i) { int c = segments[i].count; mcsum += mc[i] = segments[i].modCount; if (segments[i].containsValue(value)) return true; } boolean cleanSweep = true; //如果第一次搜寻不包含,判断是否搜寻过程中有对ConcurrentHashMap进行修改,如果有修改,则再进行一次搜寻,如果没有修改,直接返回false if (mcsum != 0) { for (int i = 0; i < segments.length; ++i) { int c = segments[i].count; if (mc[i] != segments[i].modCount) { cleanSweep = false; break; } } } if (cleanSweep) return false; } // Resort to locking all segments 加锁进行搜索 for (int i = 0; i < segments.length; ++i) segments[i].lock(); boolean found = false; try { for (int i = 0; i < segments.length; ++i) { if (segments[i].containsValue(value)) { found = true; break; } } } finally { for (int i = 0; i < segments.length; ++i) segments[i].unlock(); } return found; }迭代器抽象类:
abstract class HashIterator { int nextSegmentIndex; int nextTableIndex; HashEntry<K,V>[] currentTable; HashEntry<K, V> nextEntry; HashEntry<K, V> lastReturned; HashIterator() { //下一个segment,从后往前数 nextSegmentIndex = segments.length - 1; nextTableIndex = -1; advance(); } public boolean hasMoreElements() { return hasNext(); } final void advance() { //如果是链表结构,移动nextEntry指针 if (nextEntry != null && (nextEntry = nextEntry.next) != null) return; //如果已经到达链表尾部,则nextEntry为table中数组中下一个 while (nextTableIndex >= 0) { if ( (nextEntry = currentTable[nextTableIndex--]) != null) return; } //找到nextSegmentIndex 、nextTableIndex和nextEntry的位置,从segment最后开始查找起,为什么从最后开始呢?而不是从头? while (nextSegmentIndex >= 0) { Segment<K,V> seg = segments[nextSegmentIndex--]; if (seg.count != 0) { currentTable = seg.table; for (int j = currentTable.length - 1; j >= 0; --j) { if ( (nextEntry = currentTable[j]) != null) { nextTableIndex = j - 1; return; } } } } }KeySet内部类
//继承与AbstractSet的keySet类,方法都是引用ConcurrentHashMap外的方法 final class KeySet extends AbstractSet<K> { public Iterator<K> iterator() { return new KeyIterator(); } public int size() { return ConcurrentHashMap.this.size(); } public boolean contains(Object o) { return ConcurrentHashMap.this.containsKey(o); } public boolean remove(Object o) { return ConcurrentHashMap.this.remove(o) != null; } public void clear() { ConcurrentHashMap.this.clear(); } }Values内部类
//继承于AbstractCollection类,values可以重复,基本上也是调用ConcurrentHashMap方法 final class Values extends AbstractCollection<V> { public Iterator<V> iterator() { return new ValueIterator(); } public int size() { return ConcurrentHashMap.this.size(); } public boolean contains(Object o) { return ConcurrentHashMap.this.containsValue(o); } public void clear() { ConcurrentHashMap.this.clear(); } }