jdk1.8之前,通過segments實現,segments繼承reentrantlock,segments充當鎖的角色,每乙個table(桶)都有自己的鎖,因此jdk1.8之前concurrenthashmap採用分段鎖的機制來實現併發的更新操作,提高併發效率。
table相當於hashmap中的陣列(桶),桶裡每乙個節點包含鍵,值,hash值,稱之為hashentry,用來封裝鍵值對(key,value);
jdk1.8時,節點依舊存在(node),不存在segments,不採用分段鎖機制實現併發;
1)取消了segments欄位,採用volatile修飾table儲存資料,採用table陣列作為鎖(同步鎖);
2)將原先table陣列+鍊錶的資料結構變成table陣列+鍊錶+紅黑樹的資料結構;(在使用hash表查詢資料的時候,我們期待時間複雜度為o(1),如果只使用鍊錶,會產生大量的hash衝突,key值不能均勻分布,會使時間複雜度變為o(n),紅黑樹在最壞情況下,時間複雜度為logn )
public
class
concurrenthashmap
extends
abstractmap
implements
concurrentmap
, serializable
無參建構函式
public
concurrenthashmap
(int initialcapacity)
建立帶有指定容量的map
public
concurrenthashmap
(map<
?extendsk,
?extends
v> m)
表示可以傳入乙個map對映,將map中的所有元素新增到新的物件裡面
public
concurrenthashmap
(int initialcapacity,
float loadfactor)
傳入指定容量,和指定的載入因子
public
concurrenthashmap
(int initialcapacity,
float loadfactor,
int concurrencylevel)
給定容量,載入因子,併發級別
public v put
(k key, v value)
put方法中呼叫了putval方法 ,putval方法的實現如下:
final v putval
(k key, v value,
boolean onlyifabsent)
elseif(
(fh = f.hash)
== moved)
tab =
helptransfer
(tab, f)
;else
if(onlyifabsent // check first node without acquiring lock
&& fh == hash
&&((fk = f.key)
== key ||
(fk != null && key.
equals
(fk)))
&&(fv = f.val)
!= null)
return fv;
else
node
pred = e;if(
(e = e.next)
== null)}}
else
if(f instanceof
treebin)}
else
if(f instanceof
reservationnode
)throw
newillegalstateexception
("recursive update");
}}if(bincount !=0)
}}addcount
(1l, bincount)
;return null;
}
其中:spread(key.hashcode)是用來計算key的hash碼值。之後出現了乙個大的for迴圈(由於沒有結束判斷,所以可以看成是乙個死迴圈)
if
(tab == null ||
(n = tab.length)==0
) tab =
inittable()
;
這個判斷是用來當table為空時做hash陣列的初始化工作,呼叫了inittable方法:
private
final node
inittable()
}finally
break;}
}return tab;
}
sizectl:-1 代表初始化,0代表預設狀態,-(1+其他正在進行擴容操作的執行緒數),初始化過後,代表在此resize時map中的元素個數
在初始化的邏輯中進行如下邏輯判斷
1.首先判斷sizectl是否小於0,如果為true,則代表在多執行緒條件下,已經有執行緒在進行初始化工作,則當前執行緒執行yield方法,讓度出自己的資源,直到sizectl在其他執行緒初始化完成後被置成0,則不滿足while方法的判斷條件,跳出迴圈.
2.如果為false,代表當前執行緒可以對table進行初始化,則利用cas操作將當前的sc(即sizectl)置為-1,進入初始化的邏輯操作
3.n代表陣列長度,由於sizectl為-1,所以n取為default_capacity=16, sc=sizectl更新為0,初始化完成
elseif(
(fh = f.hash)
== moved)
tab =
helptransfer
(tab, f)
;
最後else:真正執行元素的新增操作,非首節點,採用了synchronized首元素的方法來保證執行緒安全,並且concurrenthashmap的底層採用的還是紅黑樹這種資料結構,所以當節點過多(桶數量小於64時不會轉化成紅黑樹,而只是繼續擴容。當桶的數量大於64且鍊錶結點數超過了8,才會轉化成紅黑樹),會把鍊錶轉化成紅黑樹,提高率 ConcurrentHashMap底層原始碼實現
concurrenthashmap底層原始碼實現 空構造方法 常用方法put k key,v value 呼叫putval方法 key,value,false putval key,value,false 如果key或者value為空,則丟擲空指標異常,說明不能新增空值 定義hash為hash值sp...
ConcurrentHashMap底層原理
出自jdk5新引進的concurrent包,concurrenthashmap主要解決了兩個問題 相較於只使用synchronized的hashtable提高了效能,根據具體場景進行不同的設計,盡量避免了重量級鎖。不同於hashmap,採用了fail safe弱一致性迭代器,再迭代器使用過程中,可以...
ConcurrentHashMap底層實現
concurrenthashmap融合了hashtable和hashmap二者的優勢 hashtable是做了同步的,hashmap沒有同步,所以hashmap在單執行緒情況下效率高,hashtable在多執行緒情況下,同步操作能保證程式執行的正確性 但是hashtable每次同步執行都要鎖住整個結...