1、AQS介紹?
AQS 的全稱為 AbstractQueuedSynchronizer
,翻譯過來的意思就是抽象隊(duì)列同步器。這個(gè)類在 java.util.concurrent.locks
包下面。
AQS 就是一個(gè)抽象類,主要用來構(gòu)建鎖和同步器。
public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer implements java.io.Serializable {
}
AQS 為構(gòu)建鎖和同步器提供了一些通用功能的實(shí)現(xiàn),因此,使用 AQS 能簡單且高效地構(gòu)造出應(yīng)用廣泛的大量的同步器,比如我們提到的 ReentrantLock
,Semaphore
,其他的諸如 ReentrantReadWriteLock
,SynchronousQueue
等等皆是基于 AQS 的。
2、AQS 原理?
AQS 核心思想AQS 核心思想是: 如果被請(qǐng)求的共享資源空閑,則將當(dāng)前請(qǐng)求資源的線程設(shè)置為有效的工作線程,并且將共享資源設(shè)置為鎖定狀態(tài)。如果被請(qǐng)求的共享資源被占用,那么就需要一套線程阻塞等待以及被喚醒時(shí)鎖分配的機(jī)制,這個(gè)機(jī)制 AQS 是基于 CLH 鎖 (Craig, Landin, and Hagersten locks) 實(shí)現(xiàn)的。
CLH 鎖是對(duì)自旋鎖的一種改進(jìn),是一個(gè)虛擬的雙向隊(duì)列加粗樣式(虛擬的雙向隊(duì)列即不存在隊(duì)列實(shí)例,僅存在結(jié)點(diǎn)之間的關(guān)聯(lián)關(guān)系),暫時(shí)獲取不到鎖的線程將被加入到該隊(duì)列中。AQS 將每條請(qǐng)求共享資源的線程封裝成一個(gè) CLH 隊(duì)列鎖的一個(gè)結(jié)點(diǎn)(Node
)來實(shí)現(xiàn)鎖的分配。在 CLH 隊(duì)列鎖中,一個(gè)節(jié)點(diǎn)表示一個(gè)線程,它保存著線程的引用(thread
)、 當(dāng)前節(jié)點(diǎn)在隊(duì)列中的狀態(tài)(waitStatus
)、前驅(qū)節(jié)點(diǎn)(prev
)、后繼節(jié)點(diǎn)(next
)。
CLH 隊(duì)列鎖結(jié)構(gòu)如下圖所示:
AQS(AbstractQueuedSynchronizer)的核心原理圖:
AQS 使用 int 成員變量 state
表示同步狀態(tài),通過內(nèi)置的 線程等待隊(duì)列 來完成獲取資源線程的排隊(duì)工作。
state
變量由 volatile
修飾,用于展示當(dāng)前臨界資源的獲鎖情況。
// 共享變量,使用volatile修飾保證線程可見性
private volatile int state;
另外,狀態(tài)信息 state
可以通過 protected
類型的getState()、setState()
和compareAndSetState()
進(jìn)行操作。并且,這幾個(gè)方法都是 final
修飾的,在子類中無法被重寫。
//返回同步狀態(tài)的當(dāng)前值
protected final int getState() {
return state;
}
// 設(shè)置同步狀態(tài)的值
protected final void setState(int newState) {
state = newState;
}
//原子地(CAS操作)將同步狀態(tài)值設(shè)置為給定值update如果當(dāng)前同步狀態(tài)的值等于expect(期望值)
protected final boolean compareAndSetState(int expect, int update) {
return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
以 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)的。文章來源:http://www.zghlxwxcb.cn/news/detail-645415.html
再以 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)作。文章來源地址http://www.zghlxwxcb.cn/news/detail-645415.html
到了這里,關(guān)于Java知識(shí)學(xué)習(xí)13(AQS詳解)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!