線程安全的list+map


一、Vector和SynchronizedList

1.1回顧線程安全的Vector和SynchronizedList

我們知道ArrayList是用于替代Vector的卵酪,Vector是線程安全的容器密末。因為它幾乎在每個方法聲明處都加了synchronized關(guān)鍵字來使容器安全仔涩。


如果使用Collections.synchronizedList(new ArrayList())來使ArrayList變成是線程安全的話饲常,也是幾乎都是每個方法都加上synchronized關(guān)鍵字的,只不過它不是加在方法的聲明處黍翎,而是方法的內(nèi)部



二蟆技、CopyOnWriteArrayList(Set)介紹

一般來說玩敏,我們會認(rèn)為:CopyOnWriteArrayList是同步List的替代品,CopyOnWriteArraySet是同步Set的替代品质礼。

無論是Hashtable-->ConcurrentHashMap旺聚,還是說Vector-->CopyOnWriteArrayList。JUC下支持并發(fā)的容器與老一代的線程安全類相比眶蕉,總結(jié)起來就是加鎖粒度的問題

Hashtable砰粹、Vector加鎖的粒度大(直接在方法聲明處使用synchronized)

ConcurrentHashMap、CopyOnWriteArrayList加鎖粒度小(用各種的方式來實現(xiàn)線程安全,比如我們知道的ConcurrentHashMap用了cas鎖碱璃、volatile等方式來實現(xiàn)線程安全..)

JUC下的線程安全容器在遍歷的時候不會拋出ConcurrentModificationException異常

所以一般來說弄痹,我們都會使用JUC包下給我們提供的線程安全容器,而不是使用老一代的線程安全容器嵌器。

下面我們來看看CopyOnWriteArrayList是怎么實現(xiàn)的肛真,為什么使用迭代器遍歷的時候就不用額外加鎖,也不會拋出ConcurrentModificationException異常爽航。

2.1CopyOnWriteArrayList實現(xiàn)原理

我們還是先來回顧一下COW:

如果有多個調(diào)用者(callers)同時請求相同資源(如內(nèi)存或磁盤上的數(shù)據(jù)存儲)蚓让,他們會共同獲取相同的指針指向相同的資源,直到某個調(diào)用者試圖修改資源的內(nèi)容時讥珍,系統(tǒng)才會真正復(fù)制一份專用副本(private copy)給該調(diào)用者历极,而其他調(diào)用者所見到的最初的資源仍然保持不變。優(yōu)點是如果調(diào)用者沒有修改該資源衷佃,就不會有副本(private copy)被建立趟卸,因此多個調(diào)用者只是讀取操作時可以共享同一份資源

參考自維基百科:zh.wikipedia.org/wiki/%E5%AF…

概括一下CopyOnWriteArrayList源碼注釋介紹了什么:

(1)0CopyOnWriteArrayList是線程安全容器(相對于ArrayList)氏义,底層通過復(fù)制數(shù)組的方式來實現(xiàn)锄列。

(2)CopyOnWriteArrayList在遍歷的使用不會拋出ConcurrentModificationException異常,并且遍歷的時候就不用額外加鎖

(3)元素可以為null

2.1.1看一下CopyOnWriteArrayList基本的結(jié)構(gòu)


看起來挺簡單的觅赊,CopyOnWriteArrayList底層就是數(shù)組右蕊,加鎖就交由ReentrantLock來完成。

2.1.2常見方法的實現(xiàn)

根據(jù)上面的分析我們知道如果遍歷Vector/SynchronizedList是需要自己手動加鎖的吮螺。

CopyOnWriteArrayList使用迭代器遍歷時不需要顯示加鎖饶囚,看看add()、clear()鸠补、remove()與get()方法的實現(xiàn)可能就有點眉目了萝风。

首先我們可以看看add()方法

通過代碼我們可以知道:在添加的時候就上鎖,并復(fù)制一個新數(shù)組紫岩,增加操作在新數(shù)組上完成规惰,將array指向到新數(shù)組中,最后解鎖泉蝌。

再來看看size()方法:

再來看看get()方法:

那再來看看set()方法

了歇万。

總結(jié):

(1)在修改時,復(fù)制出一個新數(shù)組勋陪,修改的操作在新數(shù)組中完成贪磺,最后將新數(shù)組交由array變量指向

(2)寫加鎖诅愚,讀不加鎖

2.1.3剖析為什么遍歷時不用調(diào)用者顯式加鎖

常用的方法實現(xiàn)我們已經(jīng)基本了解了寒锚,但還是不知道為啥能夠在容器遍歷的時候?qū)ζ溥M行修改而不拋出異常。所以,來看一下他的迭代器吧:

到這里刹前,我們應(yīng)該就可以想明白了泳赋!CopyOnWriteArrayList在使用迭代器遍歷的時候,操作的都是原數(shù)組喇喉!

2.1.4CopyOnWriteArrayList缺點

看了上面的實現(xiàn)源碼祖今,我們應(yīng)該也大概能分析出CopyOnWriteArrayList的缺點了。

內(nèi)存占用:如果CopyOnWriteArrayList經(jīng)常要增刪改里面的數(shù)據(jù)拣技,經(jīng)常要執(zhí)行add()衅鹿、set()、remove()的話过咬,那是比較耗費內(nèi)存的。

因為我們知道每次add()制妄、set()掸绞、remove()這些增刪改操作都要復(fù)制一個數(shù)組出來。

數(shù)據(jù)一致性:CopyOnWrite容器只能保證數(shù)據(jù)的最終一致性耕捞,不能保證數(shù)據(jù)的實時一致性衔掸。

從上面的例子也可以看出來,比如線程A在迭代CopyOnWriteArrayList容器的數(shù)據(jù)俺抽。線程B在線程A迭代的間隙中將CopyOnWriteArrayList部分的數(shù)據(jù)修改了(已經(jīng)調(diào)用setArray()了)敞映。但是線程A迭代出來的是原有的數(shù)據(jù)。

2.1.5CopyOnWriteSet

CopyOnWriteArraySet的原理就是CopyOnWriteArrayList磷斧。


ConcurrentHashMap

數(shù)據(jù)結(jié)構(gòu)

JDK 1.8中ConcurrentHashMap拋棄了分段鎖技術(shù)的實現(xiàn)振愿,直接采用CAS + synchronized保證并發(fā)更新的安全性,底層采用數(shù)組+鏈表+紅黑樹的存儲結(jié)構(gòu)弛饭。其包含核心靜態(tài)內(nèi)部類 Node冕末。

首先通過一張圖來看下數(shù)據(jù)結(jié)構(gòu)吧:

數(shù)據(jù)結(jié)構(gòu)圖

說明:數(shù)據(jù)結(jié)構(gòu)采用數(shù)組 + 鏈表 + 紅黑樹的方式實現(xiàn)。當(dāng)鏈表中(bucket)的節(jié)點個數(shù)超過8個時侣颂,會轉(zhuǎn)換成紅黑樹的數(shù)據(jù)結(jié)構(gòu)存儲档桃,這樣設(shè)計的目的是為了減少同一個鏈表沖突過大情況下的讀取效率。

Java8中主要做了如下優(yōu)化:

1.將Segment拋棄掉了憔晒,直接采用Node(繼承自Map.Entry)作為table元素藻肄。

2.修改時,不再采用ReentrantLock加鎖拒担,直接用內(nèi)置synchronized加鎖嘹屯,java8的內(nèi)置鎖比之前版本優(yōu)化了很多,相較ReentrantLock澎蛛,性能不并差抚垄。

3.size方法優(yōu)化,增加了CounterCell內(nèi)部類,用于并行計算每個bucket的元素數(shù)量呆馁。

內(nèi)部類和繼承關(guān)系

Java8中ConcurrentHashMap增加了很多內(nèi)部類來支持一些操作和優(yōu)化性能桐经。下面介紹幾個核心的內(nèi)部類。

ConcurrentHashMap幾個核心內(nèi)部類關(guān)系圖

(1)Node類:存放元素的key,value,hash值,next下一個鏈表節(jié)點的引用浙滤。用于bucket為鏈表時阴挣。

(2)TreeBin:內(nèi)部屬性有root,first節(jié)點纺腊,以及root節(jié)點的鎖狀態(tài)變量lockState畔咧,這是一個讀寫鎖的狀態(tài)。用于存放紅黑樹的root節(jié)點揖膜,并用讀寫鎖lockState控制在寫操作即將要調(diào)整樹結(jié)構(gòu)前誓沸,先讓讀線程完成讀操作。從鏈表結(jié)構(gòu)調(diào)整為紅黑樹時壹粟,table中索引下標(biāo)存儲的即為TreeBin拜隧。

(3)TreeNode:紅黑樹的節(jié)點,存放了父節(jié)點趁仙,左子節(jié)點洪添,右子節(jié)點的引用,以及紅黑節(jié)點標(biāo)識雀费。

(4)ForwardingNode:在調(diào)用transfer()方法期間干奢,插入bucket頭部的節(jié)點,主要用來標(biāo)識在擴容時元素的移動狀態(tài)盏袄,即是否在擴容時還有并發(fā)的插入節(jié)點忿峻,并保證該節(jié)點也能夠移動到擴容后的表中。

(5)ReservationNode:占位節(jié)點辕羽,不存儲任何信息炭菌,無實際用處,僅用于computeIfAbsent和compute方法中逛漫。

重要屬性介紹


以上的一些屬性黑低,在初始化,擴容酌毡,鏈表轉(zhuǎn)紅黑樹等方法中用到克握。屬性眾多,sizeCtl枷踏,counterCells都比較重要菩暗。

sizeCtl:即作為table初始化狀態(tài)的標(biāo)識,也用作擴容時的線程數(shù)標(biāo)識旭蠕,還用作初始和擴容后table的容量標(biāo)識停团,用處很多旷坦,不同狀態(tài)值代表的含義如下:

1、 -1:標(biāo)識table正在初始化

2佑稠、- N:標(biāo)識table正在進行擴容秒梅,并且有N - 1個線程一起在進行擴容

3、正數(shù):初始化table的大小舌胶,如果值大于初始容量大小捆蜀,則表示擴容后的table大小。

鏈接:https://juejin.im/post/5be23e6ef265da6135720d61 鏈接:http://www.reibang.com/p/85d158455861

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末幔嫂,一起剝皮案震驚了整個濱河市辆它,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌履恩,老刑警劉巖锰茉,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異切心,居然都是意外死亡洞辣,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門昙衅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人定鸟,你說我怎么就攤上這事而涉。” “怎么了联予?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵啼县,是天一觀的道長。 經(jīng)常有香客問我沸久,道長季眷,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任卷胯,我火速辦了婚禮子刮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘窑睁。我一直安慰自己挺峡,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布担钮。 她就那樣靜靜地躺著橱赠,像睡著了一般。 火紅的嫁衣襯著肌膚如雪箫津。 梳的紋絲不亂的頭發(fā)上狭姨,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天宰啦,我揣著相機與錄音,去河邊找鬼饼拍。 笑死赡模,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的惕耕。 我是一名探鬼主播纺裁,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼司澎!你這毒婦竟也來了欺缘?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤挤安,失蹤者是張志新(化名)和其女友劉穎谚殊,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蛤铜,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡嫩絮,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了围肥。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片剿干。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖穆刻,靈堂內(nèi)的尸體忽然破棺而出置尔,到底是詐尸還是另有隱情,我是刑警寧澤氢伟,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布榜轿,位于F島的核電站,受9級特大地震影響朵锣,放射性物質(zhì)發(fā)生泄漏谬盐。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一诚些、第九天 我趴在偏房一處隱蔽的房頂上張望飞傀。 院中可真熱鬧,春花似錦诬烹、人聲如沸助析。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽外冀。三九已至,卻和暖如春掀泳,著一層夾襖步出監(jiān)牢的瞬間雪隧,已是汗流浹背西轩。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留脑沿,地道東北人藕畔。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像庄拇,于是被迫代替她去往敵國和親注服。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容

  • 不足的地方請大家多多指正措近,如有其它沒有想到的常問面試題請大家多多評論溶弟,一起成長,感謝!~ String可以被繼承嗎...
    啟示錄是真的閱讀 2,935評論 3 3
  • hashmap實現(xiàn)的數(shù)據(jù)結(jié)構(gòu)瞭郑,數(shù)組辜御、桶等。 如圖所示 JDK 1.7屈张,是以數(shù)組+鏈表組成的擒权,鏈表為相同hash的鍵...
    不需要任何閱讀 828評論 0 1
  • 并發(fā)編程實踐中,ConcurrentHashMap是一個經(jīng)常被使用的數(shù)據(jù)結(jié)構(gòu)阁谆,相比于Hashtable以及Coll...
    天草二十六_簡村人閱讀 786評論 0 3
  • 1.ConcurrentHashmap簡介 在使用HashMap時在多線程情況下擴容會出現(xiàn)CPU接近100%的情況...
    huanfuan閱讀 606評論 0 2
  • 一葉蘭舟碳抄,系東門津涉,南浦青堤场绿。江城水郭村寨剖效,竹筏鸕鶿。滄浪蓑笠裳凸,一竿過、若隱丹曦劝贸。遙望眼姨谷、嵐峰疊影,繡巒夾帶如絲...
    劉小地閱讀 286評論 12 49