CopyOnWriteList源碼分析

CopyOnWriteList簡介

ArrayList是線程不安全的,于是JDK在java.util.concurrent包下新增了一個線程并發(fā)安全的List-CopyOnWriteList,中心思想就是copy-on-write刃唐。簡單來說就是讀寫分離蟆肆,讀時共享唇礁,寫時復(fù)制(原本的array)更新(且為獨(dú)占式的加鎖)扫俺,而我們下面分析的源碼實(shí)現(xiàn)就是這個思想的體現(xiàn)彤枢。

成員屬性:

一個final鎖對象lock

使用volatile修飾的array,保證寫線程更新array之后別的線程能夠看到更新后的array,但是不能保證實(shí)時性:在數(shù)組副本上添加元素之后狰晚,還沒有更新array指向新地址之前,別的線程看到的還是舊的array缴啡。

后面一個是獲取數(shù)組壁晒,一個是設(shè)置數(shù)組。

構(gòu)造方法:

無參構(gòu)造方法就是創(chuàng)建一個新的長度為0的object數(shù)組业栅,然后調(diào)用setArray方法將其設(shè)置給CopyOnWriteList的成員變量array秒咐。

添加元素add(E e)?

修改元素set(int index,E element)

刪除元素remove(int index)

獲取元素get(i)

使用get(i)可以獲取指定位置i的元素

1 獲取array數(shù)組這里的get方法也體現(xiàn)了copy-on-write-list的弱一致性問題谬晕。

2 訪問傳入入?yún)⑾聵?biāo)的元素

我們看到get過程是沒有加鎖的,假設(shè)threadA執(zhí)行1之后2之前携取,這時恰好threadB執(zhí)行remove操作攒钳,threadB或獲取獨(dú)占鎖,然后執(zhí)行寫時復(fù)制操作歹茶,即復(fù)制一個新的數(shù)組newArray夕玩,然后在newArray中執(zhí)行刪除操作,更新array惊豺。如果在執(zhí)行setArray之前ThreadA搶到CPU時間片繼續(xù)執(zhí)行代碼燎孟,那么此時get還是從舊數(shù)組里面取得元素此時元素可能已經(jīng)被刪除了,所以這就是弱一致性問題尸昧。但卻保證了最終一致性揩页。

適用場景:

讀操作可以盡可能的快,而寫即使慢一些也沒關(guān)系烹俗,在很多 應(yīng)用場景中爆侣,讀操作可能會遠(yuǎn)遠(yuǎn)多于寫操作。黑名單是最典型的場景幢妄,假如我們有一個搜索網(wǎng)站兔仰,用戶在這個網(wǎng)站的搜索框中,輸入關(guān)鍵字搜索內(nèi)容蕉鸳,但是某些關(guān)鍵字不允許被搜索乎赴,這些不能被搜索的關(guān)鍵字會被放在一個黑名單中,黑名單并不需要實(shí)時更新潮尝,可能一段時間更新一次就行了榕吼,用戶每天多次搜索時,會檢查當(dāng)前關(guān)鍵字在不在黑名單中勉失,如果在羹蚣,則不能搜索,這種讀多寫少的場景也很適合使用CopyOnWrite集合乱凿。

讀寫規(guī)則:

讀寫鎖的思想是:讀讀共享顽素,寫寫互斥,讀寫互斥徒蟆,寫讀互斥戈抄,原因是由于讀操作不會修改原有的數(shù)據(jù),因此并發(fā)讀并不會有安全問題后专;而寫操作是不安全的,所以當(dāng)寫操作時输莺,不允許有讀操作加入戚哎,也不允許第二個寫線程加入裸诽。

為了將讀取的性能發(fā)揮到極致,CopyOnWriteArrayList讀取是完全不加鎖的型凳,寫入也不會阻塞讀取操作丈冬,也就是你可以在寫入的同時進(jìn)行讀取,只有寫入和寫入之間需要進(jìn)行同步甘畅,也就是不允許多個寫入同時發(fā)生埂蕊,但是在寫入時允許讀取同時發(fā)生,這樣一來疏唾,讀操作的性能就會大幅度提升蓄氧。

CopyOnWriteArrayList思想:

我們可以這樣打個比方,比如我在寫一篇簡書或者是修改一篇簡書文章槐脏,其實(shí)我正在修改只是沒有點(diǎn)擊保存重新發(fā)布喉童,所以別人看到的就是我之前沒有修改的那一篇(舊數(shù)據(jù))。只要這時我寫完了修改完了顿天。點(diǎn)擊保存(替換地址)堂氯,而這時你們看到的就是我新修改完后的簡書文章了。

因?yàn)闊o計(jì)其數(shù)的讀者可能正在讀我那一篇簡書文章牌废,他們之間肯定是不可以阻塞的咽白,假如阻塞的話,那么就要面臨排隊(duì)讀博客了鸟缕。而且還要保證我修改簡書文章的時候晶框,讀者還能讀到簡書內(nèi)容,這時候就需要讀寫分離(讀與寫同時并發(fā)叁扫,互不影響)三妈,即達(dá)到寫有鎖,讀無鎖莫绣,讀寫直接不阻塞的效果畴蒲。

從CopyOnWriteArrayList的名字就可以看出來意思就是,當(dāng)容器需要被修改的時候对室,不直接修改當(dāng)前容器模燥,而是先將當(dāng)前容器進(jìn)行copy,復(fù)制出一個新的容器掩宜,然后修改新的容器蔫骂,完成修改之后,再將原容器的引用指向新的容器牺汤,這樣就完成了整個修改過程辽旋。

這樣做的好處就是,它利用了 不變性 原理,因?yàn)槿萜髅看涡薷亩际莿?chuàng)建新副本补胚,所以對于舊容器來說码耐,其實(shí)是不可變的,也是線程安全的溶其,無需進(jìn)一步的同步操作骚腥。我們也可以并發(fā)地讀,而不需要加鎖瓶逃,因?yàn)楫?dāng)前容器不會添加任何元素束铭,也不會有修改。

CopyOnWriteArrayList的所有操作(add,set,remove等)都是通過創(chuàng)建底層數(shù)組的新副本來實(shí)現(xiàn)的厢绝,所以CopyOnWrite容器也是一種讀寫分離的思想體現(xiàn)契沫,讀和寫使用不同的容器。

缺點(diǎn):

因?yàn)槭褂昧藢憰r復(fù)制機(jī)制代芜,所以在進(jìn)行寫操作的時候埠褪,內(nèi)存里會同時駐扎兩個對象的內(nèi)存,這一點(diǎn)會占用額外的內(nèi)存空間挤庇。

在元素較多或復(fù)雜的情況下钞速,復(fù)制的開銷也很大。

復(fù)制過程不僅會占用多的內(nèi)存嫡秕,還會消耗CPU資源渴语,會降低整體性能。

數(shù)據(jù)一致性問題:

由于CopyOnWrite容器的修改是先修改副本昆咽,所以這次修改對于其他線程來說驾凶,并不是實(shí)時能看到的,只有在修改完成之后才能體現(xiàn)出來掷酗。如果你希望寫入的數(shù)據(jù)馬上被其他線程看到的話调违,CopyOnWrite容器不適合你。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末泻轰,一起剝皮案震驚了整個濱河市技肩,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌浮声,老刑警劉巖虚婿,帶你破解...
    沈念sama閱讀 216,744評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異泳挥,居然都是意外死亡然痊,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,505評論 3 392
  • 文/潘曉璐 我一進(jìn)店門屉符,熙熙樓的掌柜王于貴愁眉苦臉地迎上來剧浸,“玉大人锹引,你說我怎么就攤上這事⌒廖茫” “怎么了粤蝎?”我有些...
    開封第一講書人閱讀 163,105評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長袋马。 經(jīng)常有香客問我,道長秸应,這世上最難降的妖魔是什么虑凛? 我笑而不...
    開封第一講書人閱讀 58,242評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮软啼,結(jié)果婚禮上桑谍,老公的妹妹穿的比我還像新娘。我一直安慰自己祸挪,他們只是感情好锣披,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,269評論 6 389
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著贿条,像睡著了一般雹仿。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上整以,一...
    開封第一講書人閱讀 51,215評論 1 299
  • 那天胧辽,我揣著相機(jī)與錄音,去河邊找鬼公黑。 笑死邑商,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的凡蚜。 我是一名探鬼主播人断,決...
    沈念sama閱讀 40,096評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼朝蜘!你這毒婦竟也來了恶迈?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,939評論 0 274
  • 序言:老撾萬榮一對情侶失蹤芹务,失蹤者是張志新(化名)和其女友劉穎蝉绷,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體枣抱,經(jīng)...
    沈念sama閱讀 45,354評論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡熔吗,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,573評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了佳晶。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片桅狠。...
    茶點(diǎn)故事閱讀 39,745評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出中跌,到底是詐尸還是另有隱情咨堤,我是刑警寧澤,帶...
    沈念sama閱讀 35,448評論 5 344
  • 正文 年R本政府宣布漩符,位于F島的核電站一喘,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏嗜暴。R本人自食惡果不足惜凸克,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,048評論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望闷沥。 院中可真熱鬧萎战,春花似錦、人聲如沸舆逃。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,683評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽路狮。三九已至虫啥,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間览祖,已是汗流浹背孝鹊。 一陣腳步聲響...
    開封第一講書人閱讀 32,838評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留展蒂,地道東北人又活。 一個月前我還...
    沈念sama閱讀 47,776評論 2 369
  • 正文 我出身青樓,卻偏偏與公主長得像锰悼,于是被迫代替她去往敵國和親柳骄。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,652評論 2 354

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