JDK 1.8 的JUC對CurrentHashMap 重新定義后做了很大的變革。我們一點(diǎn)一點(diǎn)來拆解患整,今天就先說說他的 InitTable 方法
上代碼:
關(guān)于何時(shí)初始化我們后面說Put的時(shí)候在討論眯停,今天就先說說這個(gè)InitTable
并發(fā)包是如何做到既保證并發(fā)安全又保證高性能的呢济舆?
關(guān)鍵知識(shí)點(diǎn):
1、CAS
2莺债、volatile
代碼中的高亮部分標(biāo)記了sizeCtl滋觉。
sizeCtl是何物?
看圖:
sizeCtl 默認(rèn)為0齐邦,用來控制table的初始化和擴(kuò)容操作
? ? ? ? 如果sizeCtl 為-1 則說明正在初始化
? ??????????????-N?表示有N-1個(gè)線程正在進(jìn)行擴(kuò)容操作
注意:圖二中SIZECTL中獲取的 sizeCtl的地址偏移值椎侠,是在static中初始化的。
get到了關(guān)鍵信息措拇,我們先放一邊我纪,繼續(xù)說init方法
if ((sc =sizeCtl) <0)? ??
????????Thread.yield(); // lost initialization race; just spin
else if (U.compareAndSwapInt(this, SIZECTL, sc, -1))
..... //后續(xù)省略
第一步:
????????????????是判斷SizeCtl是不是<0? 判斷是否正在初始化。如果是那就Thread.yield() 實(shí)則就只允許一個(gè)線程操作丐吓,是個(gè)自選的操作
第二步:
????????????????U.compareAndSwapInt(this, SIZECTL, sc, -1)? 這個(gè)cas的判斷地址并操作為-1
????????????????unsafe方法中的Cas 判斷了地址偏移浅悉,(SIZECTL早在static就以初始化好了)
????????????????如果比較為True 那就更新為-1。原子操作保證了安全券犁。(不明白CAS的移步百度查詢Unsafe的Cas)
????????????????同時(shí)volatile保證了順序與內(nèi)存可見性术健。
總結(jié):在第一步進(jìn)行判斷,是不能保證并發(fā)安全的粘衬,如果兩個(gè)線程同時(shí)進(jìn)入荞估,就需要Cas去保證安全比被,并且原子變更數(shù)值
當(dāng)然sizeCtl 不僅僅在init中使用,還在擴(kuò)容中使用泼舱〉茸海縱觀整個(gè)類會(huì)發(fā)現(xiàn)大量的Unsafe的方法。雖然官方并不推薦使用娇昙,
但是事實(shí)證明 Doug Lea 是你大爺尺迂,還是你大爺。