ConcurrentHashMap原始碼解析(3)

2022-06-06 03:27:05 字數 4118 閱讀 3008

此文已由作者趙計剛授權網易雲社群發布。

4、get(object key)

使用方法:

map.get("hello");
源**:

concurrenthashmap的get(object key)

/**

* 根據key獲取value

* 步驟:

* 1)根據key獲取hash值

* 2)根據hash值找到相應的segment

* 呼叫segment的get(object key, int hash)

* 3)根據hash值找出hashentry陣列中的索引index,並返回hashentry[index]

* 4)遍歷整個hashentry[index]鍊錶,找出hash和key與給定引數相等的hashentry,例如e,

* 4.1)如沒找到e,返回null

* 4.2)如找到e,獲取e.value

* 4.2.1)如果e.value!=null,直接返回

* 4.2.2)如果e.value==null,則先加鎖,等併發的put操作將value設定成功後,再返回value值

*/public v get(object key)

segment的get(object key, int hash)

/**

* 根據key和hash值獲取value

*/v get(object key, int hash) 

e = e.next;}}

return null;

}

segment的getfirst(int hash)

/**

* 根據hash值找出hashentry陣列中的索引index,並返回hashentry[index]

*/hashentrygetfirst(int hash)

segment的readvalueunderlock(hashentrye)

v readvalueunderlock(hashentrye)  finally 

}

注意點:

對於get操作而言,基本沒有鎖,只有當找到了e且e.value等於null,有可能是當下的這個hashentry剛剛被建立,value屬性還沒有設定成功,這時候我們讀到是該hashentry的value的預設值null,所以這裡加鎖,等待put結束後,返回value值

據說,上邊這一點還沒有發生過

5、remove(object key)

使用方法:

map.remove("hello");
源**:

concurrenthashmap的remove(object key)

/**

* 刪除指定key的元素

* 步驟:

* 1)根據key獲取hash值

* 2)根據hash值獲取segment

* 呼叫segment的remove(object key, int hash, object value)

* 1)count-1

* 2)獲取將要刪除的元素所在的hashentry[index]

* 3)遍歷鍊錶,

* 3.1)若沒有hash和key都與指定引數相同的節點e,返回null

* 3.2)若有e,刪除指定節點e,並將e之前的節點重新排序後,將排序後的最後乙個節點的下乙個節點指定為e的下乙個節點

* (很繞,不知道jdk為什麼這樣實現)

*/public v remove(object key)

segment的remove(object key, int hash, object value)

v remove(object key, int hash, object value) 

}return oldvalue;

} finally 

}

注意:具體的實現方式看注釋,個人感覺比較繞,所以有興趣的朋友可以按照如下步驟實現了一遍:(實現的過程可以參照hashmap的remove(object key))

6、containskey(object key)

使用方法:

map.containskey("hello")
源**:

concurrenthashmap的containskey(object key)

/**

* 是否包含指定key的資料

* 步驟:

* 1)根據key計算hash值

* 2)根據hash獲取相應的segment

* 呼叫segment的containskey(object key, int hash)

* 3)根據hash值找出hashentry陣列中的索引index,並返回hashentry[index]

* 4)遍歷整個hashentry[index]鍊錶,找出hash和key與給定引數相等的hashentry,例如e,

* 4.1)如找到e,返回true

* 4.2)如沒找到e,返回false

*/public boolean containskey(object key)

segment的containskey(object key, int hash)

boolean containskey(object key, int hash) 

}return false;

}

說明:**清晰簡單,流程步驟檢視注釋即可

7、keyset().iterator()

使用方法:

mapmap = new concurrenthashmap();

map.put("hello3", "world2");

map.put("hello2", "world");

for(string key : map.keyset())

源**不寫了。

流程:遍歷每個segment中的hashentry,完成所有物件的讀取,不加鎖。

8、size()

源**:

/**

* 計算map中的key-value對總數

* 步驟:

* 1)遍歷所有段,計算總的count值sum,計算總的modcount值

* 2)如果有資料的話(modcount!=0),再遍歷所有段一遍,計算總的count值check,在這期間只要有乙個段的modcount發生了變化,就再重複如上動作兩次

* 3)若三次後,還未成功,遍歷所有segment,分別加鎖(即建立全域性鎖),然後計算,最後釋放所有鎖

*/public int size() 

if (mcsum != 0) }}

if (check == sum)//成功

break;

}if (check != sum) 

if (sum > integer.max_value)

return integer.max_value;

else

return (int) sum;

}

在不加鎖的情況下遍歷所有segment,讀取每個segment的count和modcount,並進行統計;

完畢後,再遍歷一遍所有segment,比較modcount,是否發生了變化,若發生了變化,則再重複如上動作兩次;

若三次後,還未成功,遍歷所有segment,分別加鎖(即建立全域性鎖),然後計算,最後釋放所有鎖。

注:以如上的方式,大部分情況下,不需要加鎖就可以獲取size()

總結:

jdk1.8 concurrenthashmap的實現

免費領取驗證碼、內容安全、簡訊傳送、直播點播體驗包及雲伺服器等**

更多網易技術、產品、運營經驗分享請點選。

ConcurrentHashMap原始碼分析

hashmap 先說hashmap,hashmap是執行緒不安全 的,在併發環境下,可能會形成環狀鍊錶 hashtable hashtable和hashmap的實現原理幾乎一樣,差別無非是1.hashtable不允許key和value為null 2.hashtable是執行緒安全的。但是hashta...

ConcurrentHashMap原始碼詳解

成員變數private static final int maximum capacity 1 30 private static final int default capacity 16 static final int max array size integer.max value 8 pr...

concurrentHashMap原始碼分析

concurrenthashmap是hashmap的執行緒安全版本,內部也是使用 陣列 鍊錶 紅黑樹 的結構來儲存元素。相比於同樣執行緒安全的hashtable來說,效率等各方面都有極大地提高。在這裡可以使用上篇那個 進行測試,根據結果可以知道concurrenthashmap是執行緒安全的,由於分...