同步类的基础AbstractQueuedSynchronizer(AQS)
同步類(lèi)的基礎(chǔ)AbstractQueuedSynchronizer(AQS)
我們之前介紹了很多同步類(lèi),比如ReentrantLock,Semaphore, CountDownLatch, ReentrantReadWriteLock,FutureTask等。
AQS封裝了實(shí)現(xiàn)同步器時(shí)設(shè)計(jì)的大量細(xì)節(jié)問(wèn)題。他提供了FIFO的wait queues并且提供了一個(gè)int型的state表示當(dāng)前的狀態(tài)。
根據(jù)JDK的說(shuō)明,并不推薦我們直接使用AQS,我們通常需要構(gòu)建一個(gè)內(nèi)部類(lèi)來(lái)繼承AQS并按照需要重寫(xiě)下面幾個(gè)方法:
- tryAcquire
- tryRelease
- tryAcquireShared
- tryReleaseShared
- isHeldExclusively
在這些方法中,我們需要調(diào)用getState, setState 或者 compareAndSetState這三種方法來(lái)改變state值。
上面的方法提到了兩種操作,獨(dú)占操作(如:ReentrantLock)和共享操作(如:Semaphore,CountdownLatch)。
兩種的區(qū)別在于同一時(shí)刻能否有多個(gè)線程同時(shí)獲取到同步狀態(tài)。
比如我們運(yùn)行同時(shí)多個(gè)線程去讀,但是通知只允許一個(gè)線程去寫(xiě),那么這里的讀鎖就是共享操作,而寫(xiě)鎖就是獨(dú)占操作。
在基于QAS構(gòu)建的同步類(lèi)中,最基本的操作就是獲取操作和釋放操作。而這個(gè)state就表示的是這些獲取和釋放操作所依賴的值。
State是一個(gè)int值,你可以使用它來(lái)表示任何狀態(tài),比如ReentrantLock用它來(lái)表示所有者線程重復(fù)獲取該鎖的次數(shù)。Semaphore用它來(lái)表示剩余的許可量,而FutureTask用它來(lái)表示任務(wù)的狀態(tài)(開(kāi)始,運(yùn)行,完成或者取消)。當(dāng)然你還可以自定義額外的狀態(tài)變量來(lái)表示其他的信息。
下的偽代碼表示的是AQS中獲取和釋放操作的形式:
Acquire:while (!tryAcquire(arg)) {enqueue thread if it is not already queued;possibly block current thread;}Release:if (tryRelease(arg))unblock the first queued thread;獲取操作,首先判斷當(dāng)前狀態(tài)是否允許獲取操作,如果如果不允許,則將當(dāng)前的線程入Queue,并且有可能阻塞當(dāng)前線程。
釋放操作,則先判斷是否運(yùn)行釋放操作,如果允許,則解除queue中的thread,并運(yùn)行。
我們看一個(gè)具體的實(shí)現(xiàn):
public class AQSUsage {private final Sync sync= new Sync();private class Sync extends AbstractQueuedSynchronizer{protected int tryAcquireShared(int ignored){return (getState() ==1 )? 1: -1;}protected boolean tryReleaseShared(int ignored){setState(1);return true;}}public void release() {sync.releaseShared(0);}public void acquire() throws InterruptedException {sync.acquireSharedInterruptibly(0);} }上面的例子中,我們定義了一個(gè)內(nèi)部類(lèi)Sync,在這個(gè)類(lèi)中我們實(shí)現(xiàn)了tryAcquireShared和tryReleaseShared兩個(gè)方法,在這兩個(gè)方法中我們判斷并設(shè)置了state的值。
sync.releaseShared和sync.acquireSharedInterruptibly會(huì)分別調(diào)用tryAcquireShared和tryReleaseShared方法。
前面我們也提到了很多同步類(lèi)都是使用AQS來(lái)實(shí)現(xiàn)的,我們可以再看看其他標(biāo)準(zhǔn)同步類(lèi)中tryAcquire的實(shí)現(xiàn)。
首先看下ReentrantLock:
final boolean tryAcquire(int acquires) {final Thread current = Thread.currentThread();int c = getState();if (c == 0) {if (compareAndSetState(0, acquires)) {setExclusiveOwnerThread(current);return true;}}else if (current == getExclusiveOwnerThread()) {int nextc = c + acquires;if (nextc < 0) // overflowthrow new Error("Maximum lock count exceeded");setState(nextc);return true;}return false;}ReentrantLock只支持獨(dú)占鎖。所以它需要實(shí)現(xiàn)tryAcquire方法。除此之外它還維護(hù)了一個(gè)owner變量來(lái)保存當(dāng)前所有者線程的標(biāo)志符,從而來(lái)實(shí)現(xiàn)可重入鎖。
我們?cè)倏聪耂emaphore和CountDownLatch的實(shí)現(xiàn),因?yàn)樗麄兪枪蚕聿僮?#xff0c;所以需要實(shí)現(xiàn)tryAcqureShared方法:
final int tryAcquireShared(int acquires) {for (;;) {int available = getState();int remaining = available - acquires;if (remaining < 0 ||compareAndSetState(available, remaining))return remaining;}}本文的例子請(qǐng)參考https://github.com/ddean2009/learn-java-concurrency/tree/master/AQS
更多精彩內(nèi)容且看:
- 區(qū)塊鏈從入門(mén)到放棄系列教程-涵蓋密碼學(xué),超級(jí)賬本,以太坊,Libra,比特幣等持續(xù)更新
- Spring Boot 2.X系列教程:七天從無(wú)到有掌握Spring Boot-持續(xù)更新
- Spring 5.X系列教程:滿足你對(duì)Spring5的一切想象-持續(xù)更新
- java程序員從小工到專(zhuān)家成神之路(2020版)-持續(xù)更新中,附詳細(xì)文章教程
更多內(nèi)容請(qǐng)?jiān)L問(wèn) flydean的博客
總結(jié)
以上是生活随笔為你收集整理的同步类的基础AbstractQueuedSynchronizer(AQS)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 由于不当的执行顺序导致的死锁
- 下一篇: 非阻塞同步机制和CAS