還不懂 ConcurrentHashMap ?這份原始碼分析瞭解一下
阿新 • • 發佈:2020-04-08
上一篇文章介紹了 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