AQS是什么?有什么用雁歌?
AQS全稱AbstractQueuedSynchronizer,即抽象的隊(duì)列同步器,是一種用來(lái)構(gòu)建鎖和同步器的框架知残。
基于AQS構(gòu)建的同步器
ReentrantLock
Semaphone
CountDownLatch
ReentrantReadWriteLock
SynchronusQueue
FutureTask
優(yōu)勢(shì)
AQS解決了在實(shí)現(xiàn)同步器時(shí)設(shè)計(jì)的大量細(xì)節(jié)問(wèn)題靠瞎,例如自定義標(biāo)準(zhǔn)同步狀態(tài)、FIFO同步隊(duì)列求妹。
基于AQS來(lái)構(gòu)建同步器可以帶來(lái)很多好處乏盐。它不僅能極大地減少實(shí)現(xiàn)工作,而且也不必處理在多個(gè)位置上發(fā)生的競(jìng)爭(zhēng)問(wèn)題制恍。
它的類(lèi)及類(lèi)結(jié)構(gòu)圖如下:
原理
在AQS類(lèi)中維護(hù)了一個(gè)使用雙向鏈表Node實(shí)現(xiàn)的FIFO隊(duì)列父能,用于保存等待的線程,同時(shí)利用一個(gè)int類(lèi)型的state表示狀態(tài)净神,使用時(shí)通過(guò)繼承AQS類(lèi)并實(shí)現(xiàn)它的acquire和release方法來(lái)操作狀態(tài)何吝,來(lái)實(shí)現(xiàn)線程的同步。
以ReentrantLock為例鹃唯,state初始化為0爱榕,表示未鎖定狀態(tài)。A線程lock()時(shí)坡慌,會(huì)調(diào)用tryAcquire()獨(dú)占該鎖并將state+1黔酥。此后,其他線程再tryAcquire()時(shí)就會(huì)失敗洪橘,直到A線程unlock()到state=0(即釋放鎖)為止跪者,其它線程才有機(jī)會(huì)獲取該鎖。當(dāng)然熄求,釋放鎖之前渣玲,A線程自己是可以重復(fù)獲取此鎖的(state會(huì)累加),這就是可重入的概念抡四。但要注意柜蜈,獲取多少次就要釋放多么次,這樣才能保證state是能回到零態(tài)的指巡。
再以CountDownLatch以例淑履,任務(wù)分為N個(gè)子線程去執(zhí)行,state也初始化為N(注意N要與線程個(gè)數(shù)一致)藻雪。這N個(gè)子線程是并行執(zhí)行的秘噪,每個(gè)子線程執(zhí)行完后countDown()一次,state會(huì)CAS(Compare and Swap)減1勉耀。等到所有子線程都執(zhí)行完后(即state=0)指煎,會(huì)unpark()主調(diào)用線程蹋偏,然后主調(diào)用線程就會(huì)從await()函數(shù)返回,繼續(xù)后余動(dòng)作至壤。
Sync queue:同步隊(duì)列威始,是一個(gè)雙向鏈表。包括head節(jié)點(diǎn)和tail節(jié)點(diǎn)像街。head節(jié)點(diǎn)主要用作后續(xù)的調(diào)度黎棠。
Condition queue:非必須,單向鏈表镰绎。當(dāng)程序中存在condition的時(shí)候才會(huì)存在此鏈表中脓斩。
不同組件的使用
CountDownLatch
主要用于等待線程等待其它線程執(zhí)行后再執(zhí)行,其實(shí)現(xiàn)是通過(guò)控制計(jì)數(shù)器是否遞減到0來(lái)判斷畴栖,其它的每一個(gè)線程執(zhí)行完畢后随静,調(diào)用countDown()方法讓計(jì)數(shù)器減1,等待線程調(diào)用await()方法吗讶,直到計(jì)數(shù)器為1再執(zhí)行燎猛。
CyclicBarrier
用于等待多個(gè)線程都準(zhǔn)備好再進(jìn)行,每一個(gè)線程準(zhǔn)別好后关翎,計(jì)數(shù)器加1扛门,加到指定值后全部開(kāi)始。
Semaphore
用于控制某個(gè)資源同時(shí)可被訪問(wèn)的個(gè)數(shù)纵寝,如控制數(shù)據(jù)庫(kù)資源可以同時(shí)并發(fā)數(shù)量為20.
ReentrantReadWriteLock
讀寫(xiě)鎖论寨,用于需要同步資源時(shí)在前后加鎖/解鎖,當(dāng)一個(gè)線程獲取讀鎖后其它線程可以繼續(xù)獲取讀鎖爽茴,當(dāng)一個(gè)線程獲取寫(xiě)鎖后其它線程都需等待葬凳,因此,可能造成寫(xiě)鎖饑餓室奏,就是寫(xiě)鎖一直無(wú)法獲取火焰。
StampLock
類(lèi)似讀寫(xiě)鎖的功能和使用方法,不過(guò)有一下兩點(diǎn)不同:
- 每次獲取鎖會(huì)得到一個(gè)long類(lèi)型的stamp的返回值胧沫,解鎖時(shí)需要將其回傳昌简。
- 有樂(lè)觀讀操作,適合讀多寫(xiě)少情況绒怨,指當(dāng)資源被讀鎖鎖定時(shí)纯赎,會(huì)根據(jù)資源是否被變更,進(jìn)行讀取操作南蹂,而不是不允許讀操作犬金。
Condition
配合AQS鎖實(shí)現(xiàn)的線程中斷/等待機(jī)制,將等待的線程移入condition維護(hù)的隊(duì)列,并通過(guò)condition控制中斷/等待晚顷。
參考文章
https://www.xuxueli.com/blog/
https://juejin.im/post/5d08a0be6fb9a07edd2a1438