1. 程式人生 > >還不懂 ConcurrentHashMap ?這份原始碼分析瞭解一下

還不懂 ConcurrentHashMap ?這份原始碼分析瞭解一下

上一篇文章介紹了 HashMap 原始碼,反響不錯,也有很多同學發表了自己的觀點,這次又來了,這次是 `ConcurrentHashMap ` 了,作為執行緒安全的HashMap ,它的使用頻率也是很高。那麼它的儲存結構和實現原理是怎麼樣的呢? ## 1. ConcurrentHashMap 1.7 ### 1. 儲存結構 ![Java 7 ConcurrentHashMap 儲存結構](https://cdn.jsdelivr.net/gh/niumoo/cdn-assets/2020/image-20200405151029416.png) Java 7 中 ConcurrentHashMap 的儲存結構如上圖,ConcurrnetHashMap 由很多個 Segment 組合,而每一個 Segment 是一個類似於 HashMap 的結構,所以每一個 HashMap 的內部可以進行擴容。但是 Segment 的個數一旦**初始化就不能改變**,預設 Segment 的個數是 16 個,你也可以認為 ConcurrentHashMap 預設支援最多 16 個執行緒併發。 ### 2. 初始化 通過 ConcurrentHashMap 的無參構造探尋 ConcurrentHashMap 的初始化流程。 ```java /** * Creates a new, empty map with a default initial capacity (16), * load factor (0.75) and concurrencyLevel (16). */ public ConcurrentHashMap() { this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL); } ``` 無參構造中呼叫了有參構造,傳入了三個引數的預設值,他們的值是。 ```java /** * 預設初始化容量 */ static final int DEFAULT_INITIAL_CAPACITY = 16; /** * 預設負載因子 */ static final float DEFAULT_LOAD_FACTOR = 0.75f; /** * 預設併發級別 */ static final int DEFAULT_CONCURRENCY_LEVEL = 16; ``` 接著看下這個有參建構函式的內部實現邏輯。 ```java @SuppressWarnings("unchecked") public ConcurrentHashMap(int initialCapacity,float loadFactor, int concurrencyLevel) { // 引數校驗 if (!(loadFactor > 0) || initialCapacity < 0 || concurrencyLevel <= 0) throw new IllegalArgumentException(); // 校驗併發級別大小,大於 1<<16,重置為 65536 if (concurrencyLevel > MAX_SEGMENTS) concurrencyLevel = MAX_SEGMENTS; // Find power-of-two sizes best matching arguments // 2的多少次方 int sshift = 0; int ssize = 1; // 這個迴圈可以找到 concurrencyLevel 之上最近的 2的次方值 while (ssize < concurrencyLevel) { ++sshift; ssize <<= 1; } // 記錄段偏移量 this.segmentShift = 32 - sshift; // 記錄段掩碼 this.segmentMask = ssize - 1; // 設定容量 if (initialCapacity > MAXIMUM_CAPACITY) initialCapacity = MAXIMUM_CAPACITY; // c = 容量 / ssize ,預設 16 / 16 = 1,這裡是計算每個 Segment 中的類似於 HashMap 的容量 int c = initialCapacity / ssize; if (c * ssize < initialCapacity) ++c; int cap = MIN_SEGMENT_TABLE_CAPACITY; //Segment 中的類似於 HashMap 的容量至少是2或者2的倍數 while (cap < c) cap <<= 1; // create segments and segments[0] // 建立 Segment 陣列,設定 segments[0] Segment