總結:
分段機制:segment,每段加reentrantLock可重入鎖
定位元素:1 找segment數組下標 2 找segment的HashEntry數組下標
get方法:不需要加鎖足陨,value值使用了volatile關鍵字修飾
put方法:hash計算段---鎖定段---hash計算HashEntry數組---若超多閾值---擴容---釋放幻捏;put過程中會modCount+1佑菩,為了后續(xù)的計算大小
size()方法:為了求Map的大小页藻,需要全局鎖旧乞,但是性能差吊洼;于是采用modCount計算器,用于記錄段的大泄辔!康二;
ConcurrentHashMap的弱一致性:clear時,是不加鎖的勇蝙,所以多線程中沫勿,可能出現數據不一致;
因為沒有全局的鎖浅蚪,在清除完一個segments之后藕帜,正在清理下一個segments的時候,已經清理segments可能又被加入了數據惜傲,因此clear返回的時候,ConcurrentHashMap中是可能存在數據的贝攒。因此盗誊,clear方法是弱一致的。
ConcurrentHashMap的弱一致性主要是為了提升效率,是一致性與效率之間的一種權衡哈踱。要成為強一致性荒适,就得到處使用鎖,甚至是全局鎖开镣,這就與Hashtable和同步的HashMap一樣了刀诬。
而在迭代時,ConcurrentHashMap使用了不同于傳統(tǒng)集合的快速失敗迭代器(見之前的文章《JAVA API備忘---集合》)的另一種迭代方式邪财,我們稱為弱一致迭代器陕壹。在這種迭代方式中,當iterator被創(chuàng)建后集合再發(fā)生改變就不再是拋出ConcurrentModificationException树埠,取而代之的是在改變時new新的數據從而不影響原有的數據糠馆,iterator完成后再將頭指針替換為新的數據,這樣iterator線程可以使用原來老的數據怎憋,而寫線程也可以并發(fā)的完成改變又碌,更重要的,這保證了多個線程并發(fā)執(zhí)行的連續(xù)性和擴展性绊袋,是性能提升的關鍵毕匀。
詳情:
ConcurrentHashMap基本思想:
ConcurrentHashMap數據結構
ConcurrentHashMap的初始化
ConcurrentHashMap的get方法
ConcurrentHashMap的put方法
ConcurrentHashMap的size方法
ConcurrentHashMap的弱一致性
因為沒有全局的鎖,在清除完一個segments之后癌别,正在清理下一個segments的時候期揪,已經清理segments可能又被加入了數據,因此clear返回的時候规个,ConcurrentHashMap中是可能存在數據的凤薛。因此,clear方法是弱一致的诞仓。
舉2個比較簡單的例子就可以看出ConcurrentHashMap的弱一致性缤苫。
第一個,就是clear方法墅拭。假設線程1執(zhí)行到Segment[0].clear()的時候活玲,Segment[0]中的元素元素已經被clear,但是線程2此時可以在Segment[0]中增加元素(clear不需要加鎖)谍婉,這樣線程1執(zhí)行結束的時候就ConcurrentHashMap并不是空的舒憾。
第二個例子,判斷key是否存在穗熬,不存在則進行put镀迂。假設線程1判斷key不存在后掛起,線程2判斷key也不存在唤蔗,然后線程2執(zhí)行put操作探遵,之后線程1執(zhí)行put操作窟赏,此時線程2讀取到的會是線程1設置的值而不是線程2設置的值。當然此時應該是應用putIfAbsent方法箱季。
小結
ConcurrentHashMap在設計思路對效率和一致性上的平衡以及一些lock-free的方法非常值得借鑒涯穷,同時注意雖然類本身是線程安全的,但是不要認為使用該類就一定是線程安全的藏雏。