7:Java并發(fā)容器和框架

1:ConcurrentHashMap的實現(xiàn)原理和使用

(1)先說一下HashMap?HashMap在并發(fā)執(zhí)行put操作時會引起死循環(huán)勋篓,是以為多線程會導致它的Entry鏈表形成環(huán)形數(shù)據(jù)結(jié)構(gòu)季率。一旦形成環(huán)形數(shù)據(jù)結(jié)構(gòu)膝迎,Entry的next節(jié)點永遠不為空污抬。

HashTable:所有訪問它的線程必須競爭同一把鎖。

(2)ConcurrentHashMap使用鎖分段技術(shù)遣妥。使用的鎖為ReentrentLock.

(3)定位Segment:ConcurrentHashMap會使用Wang/Jenkins has的變種算法對元素的hasCode進行一次再散列品姓。

(4)HashMap的初始化方法是通過initialCapacity,loadFactory和concurrentLevel等幾個參數(shù)來初始化segment數(shù)組、段偏移量segmentShift蜕猫、段掩碼segmentMask和每個segment里的HashEntry數(shù)組來實現(xiàn)的寂曹。

(5)get操作:先經(jīng)過一次再散列(使用key的hashCode),然后使用這個散列值通過散列運算定位到Segment,在通過散列算法定位到元素。高效原因:整個過程不需要加鎖隆圆。它的get方法將要使用的共享變量都定位成了valatile類型漱挚。如:用于統(tǒng)計當前Segement大小的count字段和用于存儲值的HashEntry的value。由于使用了java的內(nèi)存模型happen-before原則渺氧,能夠保證validate字段的寫入先于讀旨涝。所以get操作使用能夠讀取到最新的值。

volatile替換鎖的經(jīng)典場景侣背。

注意:定位segment使用的是元素的hashcode通過再散列后得到的值的高位白华,而定位HashEntry直接使用的是再散列后的值。

(6)put操作:第一步贩耐,判斷是否需要對Segment里的HashEntry數(shù)組進行擴容弧腥;第二步,定位添加元素的位置潮太,然后將其放在HashEntry數(shù)組里管搪。

A: 怎么擴容?

創(chuàng)建一個容量是原來容量2倍的數(shù)組铡买,然后將原數(shù)組里的元素進行再散列后插入到新的數(shù)組里更鲁。為了高效,只是對某個Segment進行擴容寻狂。

(7)size操作

ConcurrentHashMap的做法是先嘗試2次通過不鎖住Segment的方式來統(tǒng)計各個Segment大小岁经。如果統(tǒng)計過程中,容器的count發(fā)生了變化蛇券,則采用加鎖的方式來統(tǒng)計所有Segment的大小缀壤。

A:ConcurrentHashMap是如何判斷在統(tǒng)計的時候容器是否發(fā)生變化呢?

使用modCount變量纠亚,在put塘慕、remove、clean方法里操作元素前都會將變量modeCount進行加1蒂胞,那么在統(tǒng)計size前后比較modCount是否發(fā)生變化即可知道图呢。

2:ConcurrentHashLinkedQueue

(1)類圖

由head節(jié)點和tail節(jié)點組成。每個節(jié)點Node由節(jié)點元素item和指向下一個節(jié)點next的引用組成骗随。默認情況下head節(jié)點存儲的元素為空蛤织,tail節(jié)點等于head節(jié)點。

(2)入隊實現(xiàn)原理:使用CAS算法來入隊鸿染。入隊過程干兩件事:第一是定位出為尾節(jié)點指蚜;第二是使用CAS算法將入隊節(jié)點設(shè)置成尾節(jié)點的next節(jié)點,如不成功則重試涨椒。tail節(jié)點不一定為尾節(jié)點摊鸡。

注意:入隊方法永遠返回true绽媒,所以不要通過返回值判斷入隊是否成功。

(3)出隊實現(xiàn)原理:

出隊列就是從隊列里返回一個節(jié)點元素免猾,并清空該節(jié)點對元素的引用是辕。

3:Java中的阻塞隊列

(1)什么是阻塞隊列?

BlockingQueue是一個支持兩個附加操作的隊列猎提。

支持阻塞的插入方法:當隊列滿時获三,隊列會阻塞插入元素的線程,直到隊列不滿忧侧。

支持阻塞的移除方法:在隊列為空時石窑,獲取元素的線程會等待隊列變?yōu)榉强铡?/p>

阻塞隊列不可用時:插入和移除提供的4種處理方式牌芋。

注意:如果是無界阻塞隊列蚓炬,隊列不可能會出現(xiàn)滿的情況,所以使用put或offer方法永遠不會被阻塞躺屁,而且使用offfer方法永遠返回true.

(2)java里的阻塞隊列

a: ArrayBlockingQueue:一個由數(shù)組結(jié)構(gòu)組成的有界阻塞隊列肯夏。默認情況下是不保證線程公平訪問隊列。構(gòu)造函數(shù)new ArrayBlockingQueue(1000 , true),第二個參數(shù)為true犀暑,可以保證公平訪問隊列驯击。底層實現(xiàn)方式為ReentrantLock.

b: LinkedBlockingQueue:一個由鏈表組成的有界阻塞隊列。

c: PriorityBlockingQueue:一個支持優(yōu)先級排序的無界阻塞隊列耐亏。

d : DelayQueue:一個使用優(yōu)先級隊列實現(xiàn)的無界阻塞隊列徊都。

e : SynchronousQueue:一個不存儲元素的阻塞隊列。非常適合傳遞性場景广辰,負責把生產(chǎn)者線程處理的數(shù)據(jù)直接傳遞給消費者線程暇矫。

f : LinkedTransferQueue:一個由鏈表結(jié)構(gòu)組成的無界阻塞隊列。其中的transfer方法可以把生產(chǎn)者傳入的元素立刻傳輸給消費者择吊。

g : LinkedBlockingDeque:一個由鏈表結(jié)構(gòu)組成的雙向阻塞隊列李根。雙向隊列經(jīng)典運用場景:工作竊取模式。

(3)阻塞隊列的實現(xiàn)原理

如何設(shè)計阻塞隊列几睛?如何生產(chǎn)者和消費者進行高效的通信房轿?(如果隊列為空,消費者一直等待所森,當生產(chǎn)者添加元素時囱持,消費者是如何知道當前隊列里有元素呢?)

實現(xiàn)方式1:使用通知模式實現(xiàn)焕济。即當生產(chǎn)者往滿的隊列里添加元素時會阻塞(例如:LockSupport.park(this)可以實現(xiàn))住生產(chǎn)者纷妆,當消費者消費了一個隊列中的元素后,會通知(例如:Condition可以實現(xiàn))生產(chǎn)者當前隊列可用吼蚁。

4:Fork/Join框架

(1)工作原理

ForkJoinPool由ForkJoinTask數(shù)組和ForkJoinWorkerThread數(shù)組組成凭需,F(xiàn)orkJoinTask數(shù)組負責將存放程序提交給ForkJoinPool的任務问欠,而ForkJoinWorkerThread數(shù)組負責執(zhí)行這些任務。

A:ForkJoinTask的fork方法實現(xiàn)原理

當調(diào)用ForkJoinTasks的fork方法時粒蜈,程序會調(diào)用ForkJoinWorkThread的pushTask方法異步地執(zhí)行這個任務顺献,然后立即返回結(jié)果。

ForkJoinWorkThread的pushTask方法把當前任務存放在ForkJoinTask數(shù)組隊列里枯怖。然后再調(diào)用ForkJoinPool的signalWork方法喚醒或創(chuàng)建一個工作線程來執(zhí)行任務注整。

B:ForkJoinTask的join方法實現(xiàn)原理

join方法的主要作用是阻塞當前線程并等待獲取結(jié)果。

(2)Fork/Join框架是Java7提供的一個用于并行執(zhí)行任務的框架度硝,是一個把大任務分割成若干個小任務肿轨,最終匯總每個小任務結(jié)果后得到大任務結(jié)果的框架。

(3)工作竊取算法(work-stealing)是指某個線程從其他隊列里竊取任務來執(zhí)行蕊程。

工作竊取的運行流程入下圖所示:

通常做法:使用雙端隊列椒袍。被竊取任務的線程永遠從雙端隊列的頭部拿任務執(zhí)行,而竊取任務的線程永遠從雙端隊列的尾部拿任務執(zhí)行藻茂。

優(yōu)點:充分利用線程進行并行計算驹暑,減少線程間的競爭。

缺點:雙端隊列里只有一個任務時辨赐,還是存在競爭优俘。該算法會消耗更多的系統(tǒng)資源,比如創(chuàng)建多個線程和多個雙端隊列掀序。

(4)Fork/Join框架的核心:

a: ?ForkJoinTask:首先創(chuàng)建一個ForkJoin任務帆焕。它提供在任務中執(zhí)行fork和join操作的機制。通常繼承它的2個子類:

RecursiveAction:用于沒有返回結(jié)果的任務不恭。

RecursiveTask:用于有返回結(jié)果的任務叶雹。

b: ?ForkJoinPool:ForkJoinTask需要通過ForkJoinPool來執(zhí)行。

任務分割出的子任務會添加到當前工作線程所維護的雙端隊列中县袱,進入隊列的頭部浑娜。當一個工作線程的隊列里暫時沒有任務時,它會隨機從其他工作線程的隊列的尾部獲取一個任務式散。

(5)Fork/Join框架的異常處理

提供isCompletedAbnormally方法來檢查任務是否已經(jīng)拋出異辰钤猓或者已經(jīng)被取消了。并且可以通過ForkJoinTask的getException方法獲取異常暴拄,它返回Throwable對象漓滔,如果任務取消了則返回CancellationException。如果任務沒有完成或者沒有拋出異常則返回null乖篷。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末响驴,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子撕蔼,更是在濱河造成了極大的恐慌豁鲤,老刑警劉巖秽誊,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異琳骡,居然都是意外死亡锅论,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進店門楣号,熙熙樓的掌柜王于貴愁眉苦臉地迎上來最易,“玉大人,你說我怎么就攤上這事炫狱≡謇粒” “怎么了?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵视译,是天一觀的道長嬉荆。 經(jīng)常有香客問我,道長憎亚,這世上最難降的妖魔是什么员寇? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任弄慰,我火速辦了婚禮第美,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘陆爽。我一直安慰自己什往,他們只是感情好,可當我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布慌闭。 她就那樣靜靜地躺著别威,像睡著了一般。 火紅的嫁衣襯著肌膚如雪驴剔。 梳的紋絲不亂的頭發(fā)上省古,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天,我揣著相機與錄音丧失,去河邊找鬼豺妓。 笑死,一個胖子當著我的面吹牛布讹,可吹牛的內(nèi)容都是我干的琳拭。 我是一名探鬼主播,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼描验,長吁一口氣:“原來是場噩夢啊……” “哼白嘁!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起膘流,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤絮缅,失蹤者是張志新(化名)和其女友劉穎鲁沥,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體耕魄,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡黍析,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了屎开。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片阐枣。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖奄抽,靈堂內(nèi)的尸體忽然破棺而出蔼两,到底是詐尸還是另有隱情,我是刑警寧澤逞度,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布额划,位于F島的核電站,受9級特大地震影響档泽,放射性物質(zhì)發(fā)生泄漏俊戳。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一馆匿、第九天 我趴在偏房一處隱蔽的房頂上張望抑胎。 院中可真熱鬧,春花似錦渐北、人聲如沸阿逃。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽恃锉。三九已至,卻和暖如春呕臂,著一層夾襖步出監(jiān)牢的瞬間破托,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工歧蒋, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留土砂,地道東北人。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓疏尿,卻偏偏與公主長得像瘟芝,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子褥琐,可洞房花燭夜當晚...
    茶點故事閱讀 42,901評論 2 345

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