ConcurrentHashMap底層分析

2021-10-08 09:52:08 字數 3337 閱讀 4215

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每次同步執行都要鎖住整個結...