<p><strong>Note that this implementation is not synchronized.</strong> If multiple threads access a hash map concurrently, and at least one of the threads modifies the map structurally, it <i>must</i> be synchronized externally. (A structural modification is any operation that adds or deletes one or more mappings; merely changing the value associated with a key that an instance already contains is not a structural modification.) This is typically accomplished by synchronizing on some object that naturally encapsulates the map.
voidcreateEntry(int hash, K key, V value, int bucketIndex) { //先保存这个位置本来的元素 Entry<K,V> e = table[bucketIndex]; //将新来的元素头插 table[bucketIndex] = newEntry<>(hash, key, value, e); size++; }
这是一个简单的头插法,试想一下,假如有两个线程A和B都往同一个hashmap中写元素,恰好这两个元素算出来的索引是一样的,B线程执行到Entry<K,V> e = table[bucketIndex]后时间片用完,获取了桶中第一个元素后就挂起了,然后线程A进入这个方法并执行完,这时候看似A线程成功将它所操作的元素插入了进来,等到B线程的时间片来临时,B线程继续上次停止的地方执行,因为A线程和B线程获取的是相同的头元素,所以B线程的插入会覆盖之前B线程的操作。
privatevoidrehash(HashEntry<K,V> node) { /* * Reclassify nodes in each list to new table. Because we * are using power-of-two expansion, the elements from * each bin must either stay at same index, or move with a * power of two offset. We eliminate unnecessary node * creation by catching cases where old nodes can be * reused because their next fields won't change. * Statistically, at the default threshold, only about * one-sixth of them need cloning when a table * doubles. The nodes they replace will be garbage * collectable as soon as they are no longer referenced by * any reader thread that may be in the midst of * concurrently traversing table. Entry accesses use plain * array indexing because they are followed by volatile * table write. */ HashEntry<K,V>[] oldTable = table; intoldCapacity= oldTable.length; intnewCapacity= oldCapacity << 1; threshold = (int)(newCapacity * loadFactor); HashEntry<K,V>[] newTable = (HashEntry<K,V>[]) newHashEntry[newCapacity]; intsizeMask= newCapacity - 1; for (inti=0; i < oldCapacity ; i++) { HashEntry<K,V> e = oldTable[i]; if (e != null) { HashEntry<K,V> next = e.next; intidx= e.hash & sizeMask; if (next == null) // Single node on list newTable[idx] = e; else { // Reuse consecutive sequence at same slot HashEntry<K,V> lastRun = e; intlastIdx= idx; for (HashEntry<K,V> last = next; last != null; last = last.next) { intk= last.hash & sizeMask; //1. 这里就是遍历当前链表,找到最后一个不在原桶中的元素,那么这个元素后面的所有元素也都不在原桶中。 if (k != lastIdx) { lastIdx = k; lastRun = last; } } newTable[lastIdx] = lastRun; // Clone remaining nodes for (HashEntry<K,V> p = e; p != lastRun; p = p.next) { Vv= p.value; inth= p.hash; intk= h & sizeMask; HashEntry<K,V> n = newTable[k]; newTable[k] = newHashEntry<K,V>(h, p.key, v, n); } } } } intnodeIndex= node.hash & sizeMask; // add the new node node.setNext(newTable[nodeIndex]); newTable[nodeIndex] = node; table = newTable; }
/** * Base counter value, used mainly when there is no contention, * but also as a fallback during table initialization * races. Updated via CAS. */ privatetransientvolatilelong baseCount;
/** * A padded cell for distributing counts. Adapted from LongAdder * and Striped64. See their internal docs for explanation. */ @sun.misc.Contended staticfinalclassCounterCell { volatilelong value; CounterCell(long x) { value = x; } }