此文已由作者趙計剛授權網易雲社群發布。
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是執行緒安全的,由於分...