ConcurrentHashMap數據結構在JDK1.7中的實現是二維數組加鏈表的結構,下面是畫出來的鳥瞰圖。數組
列出來的都是些重要參數,影響了ConcurrentHashMap的初始容量、擴容因子、默認的線程併發量、嘗試次數等等安全
//默認容量。這裏須要說明下,跟HashMap的做用不同,它不是直接控制HashEntry的容量,而是經過運行間接的得出。 static final int DEFAULT_INITIAL_CAPACITY = 16; //負載因子。 static final float DEFAULT_LOAD_FACTOR = 0.75f; //默認併發等級。控制segments數組的長度,即ConcurrentHashMap的最大線程併發量。 static final int DEFAULT_CONCURRENCY_LEVEL = 16; //嘗試次數。某些方法,例如size()等,會用到。具體做用是方法運行到指定次數之後還不是預期的結果就對方法進行加鎖,再運行。 static final int RETRIES_BEFORE_LOCK = 2;
這裏就列出幾個有表明性的方法,不涉及到過多的細節,主要想學習設計思路。在講代碼的時候會隱藏掉一些細節,並用註釋代替這段代碼的做用,大部分狀況下均可以忽略它的做用,儘可能讓你們把更多的注意力放在主要代碼上。數據結構
public ConcurrentHashMap(int initialCapacity, float loadFactor, int concurrencyLevel) { code_1 //三個參數都必須大於0,不然拋出異常。 code_2 //concurrencyLevel大於65536時,設爲65536 // Find power-of-two sizes best matching arguments int sshift = 0;//這個不不知道意義是啥 int ssize = 1;//segments數組長度。 //每次循環至關於 ssize = 2^n,默認concurrencyLevel=16,那麼ssize=16,sshift=4 while (ssize < concurrencyLevel) { ++sshift; ssize <<= 1; } //這兩個參數的做用後面會提到 this.segmentShift = 32 - sshift; this.segmentMask = ssize - 1; code_3 //initialCapacity大於1073741824 時,設爲1073741824 code_4 //必定的運算得出 cap,這裏只討論 cap=2的默認狀況。感興趣的能夠本身看源碼 int cap = MIN_SEGMENT_TABLE_CAPACITY; //建立 segment[]和初始化segment[0],segment[0]的做用給其餘位置初始化時提供參數。 Segment<K,V> s0 = new Segment<K,V>(loadFactor, (int)(cap * loadFactor), (HashEntry<K,V>[])new HashEntry[cap]); Segment<K,V>[] ss = (Segment<K,V>[])new Segment[ssize]; UNSAFE.putOrderedObject(ss, SBASE, s0); // ordered write of segments[0] this.segments = ss; }
總結來講構方法作的就時建立segments[]和初始化 0 位置多線程
ConcurrentHashMap的 public V put(K key, V value) { Segment<K,V> s; code_1// value不能爲空,不然異常 code_2// 計算key在segments的下標 int j = XX; if ((s = (Segment<K,V>)UNSAFE.getObject // nonvolatile; recheck (segments, (j << SSHIFT) + SBASE)) == null) // in ensureSegment //若是爲空就初始化 s = ensureSegment(j); //使用segment的 return s.put(key, hash, value, false); }
有時間再接着寫把。。。。。。。。。。。併發