java需要关注的知识点---ConcurrentHashMap
ConcurrentHashMap默认初始大小 16,临界值:12:基数:0.75
1.ConcurrentHashMap是一个线程安全的hashMap。相对hashMap多出以下一些特殊属性:
//默认能够同时运行的线程数目 static final int DEFAULT_CONCURRENCY_LEVEL = 16; //最大同时运行的线程数目 static final int MAX_SEGMENTS = 1 << 16; // slightly conservative
static final class HashEntry<K,V> { final K key; final int hash; volatile V value; 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; }@SuppressWarnings("unchecked")static final <K,V> HashEntry<K,V>[] newArray(int i) { return new HashEntry[i];} }static final class Segment<K,V> extends ReentrantLock implements Serializable {.....} V readValueUnderLock(HashEntry<K,V> e) { lock(); try { return e.value; } finally { unlock(); } }/** * Reads value field of an entry under lock. Called if value * field ever appears to be null. This is possible only if a * compiler happens to reorder a HashEntry initialization with * its table assignment, which is legal under memory model * but is not known to ever occur. */
public V put(K key, V value) { if (value == null) throw new NullPointerException(); int hash = hash(key.hashCode()); return segmentFor(hash).put(key, hash, value, false); }V put(K key, int hash, V value, boolean onlyIfAbsent) { lock(); try { int c = count; if (c++ > threshold) // ensure capacity rehash(); 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) { oldValue = e.value; if (!onlyIfAbsent) e.value = value; } else { oldValue = null; ++modCount; tab[index] = new HashEntry<K,V>(key, hash, first, value); count = c; // write-volatile } return oldValue; } finally { unlock(); } void rehash() { HashEntry<K,V>[] oldTable = table; int oldCapacity = oldTable.length; //如果数组的长度大于或等于临界值,数组不再进行扩容。 if (oldCapacity >= MAXIMUM_CAPACITY) return; //扩充数组容量为原来大小的两倍。 HashEntry<K,V>[] newTable = HashEntry.newArray(oldCapacity<<1); //重新计算临界值 threshold = (int)(newTable.length * loadFactor); int sizeMask = newTable.length - 1; 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) { HashEntry<K,V> next = e.next; //获取该链表在数组新的下标 int idx = e.hash & sizeMask; //该链表不存在后续节点,直接把该链表存入新数组,无需其他操作 if (next == null) newTable[idx] = e; else { // 存在后续节点,使用临时变量存储该链表,假设当前节点是最后节点。 HashEntry<K,V> lastRun = e; //获取下标 int lastIdx = idx; //遍历该链表的后续节点 for (HashEntry<K,V> last = next; last != null; last = last.next) { //获取后一个节点的index int k = last.hash & sizeMask; //如果后一个节点的index值和前一个不相同, //则使用后节点的index覆盖前一个节点并且设置该节点为最后节点,依次 //做相同的操作,直到链表的最后一个节点。 if (k != lastIdx) { lastIdx = k; lastRun = last; } } //把链表最后节点的值传递给数组 //该数组下标为最后获取到的下标 newTable[lastIdx] = lastRun; // 遍历老数组下得到的链表的节点值,复制到新的扩容后的数组中。 for (HashEntry<K,V> p = e; p != lastRun; p = p.next) { //计算链表在新数组的下标 int k = p.hash & sizeMask; //获取数组k下标的链表值。 HashEntry<K,V> n = newTable[k]; //把获取到的链表作为需要插入的新的entry的后续节点。 newTable[k] = new HashEntry<K,V>(p.key, p.hash, n, p.value); } } } } //把扩容后的数组返回 table = newTable; } public V remove(Object key) {int hash = hash(key.hashCode()); return segmentFor(hash).remove(key, hash, null); } V remove(Object key, int hash, Object value) { lock(); try { int c = count - 1; 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; 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; HashEntry<K,V> newFirst = e.next; 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(); } }