天天看點

死磕Java并發:J.U.C之AQS簡介

Java的内置鎖一直都是備受争議的,在JDK 1.6之前,synchronized這個重量級鎖其性能一直都是較為低下,雖然在1.6後,進行大量的鎖優化政策(死磕Java并發:深入分析synchronized的實作原理),但是與Lock相比synchronized還是存在一些缺陷的:雖然synchronized提供了便捷性的隐式擷取鎖釋放鎖機制(基于JVM機制),但是它卻缺少了擷取鎖與釋放鎖的可操作性,可中斷、逾時擷取鎖,且它為獨占式在高并發場景下性能大打折扣。

在介紹Lock之前,我們需要先熟悉一個非常重要的元件,掌握了該元件JUC包,下面很多問題都不在是問題了。

該元件就是AQS。

AQS,AbstractQueuedSynchronizer,即隊列同步器。它是建構鎖或者其他同步元件的基礎架構(如ReentrantLock、ReentrantReadWriteLock、Semaphore等),JUC并發包的作者(Doug Lea)期望它能夠成為實作大部分同步需求的基礎。它是JUC并發包中的核心基礎元件。

AQS解決了實作同步器時涉及當的大量細節問題,例如擷取同步狀态、FIFO同步隊列。基于AQS來建構同步器可以帶來很多好處,它不僅能夠極大地減少實作工作,而且也不必處理在多個位置上發生的競争問題。

在基于AQS建構的同步器中,隻能在一個時刻發生阻塞,進而降低上下文切換的開銷,提高了吞吐量。同時在設計AQS時充分考慮了可伸縮行,是以J.U.C中所有基于AQS建構的同步器均可以獲得這個優勢。

AQS的主要使用方式是繼承,子類通過繼承同步器并實作它的抽象方法來管理同步狀态。

AQS使用一個int類型的成員變量state來表示同步狀态,當state>0時表示已經擷取了鎖,當state = 0時表示釋放了鎖。它提供了三個方法(getState()、setState(int newState)、compareAndSetState(int expect,int update))來對同步狀态state進行操作,當然AQS可以確定對state的操作是安全的。

AQS通過内置的FIFO同步隊列來完成資源擷取線程的排隊工作,如果目前線程擷取同步狀态失敗(鎖)時,AQS則會将目前線程以及等待狀态等資訊構造成一個節點(Node)并将其加入同步隊列,同時會阻塞目前線程,當同步狀态釋放時,則會把節點中的線程喚醒,使其再次嘗試擷取同步狀态。

AQS主要提供了如下一些方法:

  1. getState():傳回同步狀态的目前值;
  2. setState(int newState):設定目前同步狀态;
  3. compareAndSetState(int expect, int update):使用CAS設定目前狀态,該方法能夠保證狀态設定的原子性;
  4. tryAcquire(int arg):獨占式擷取同步狀态,擷取同步狀态成功後,其他線程需要等待該線程釋放同步狀态才能擷取同步狀态;
  5. tryRelease(int arg):獨占式釋放同步狀态;
  6. tryAcquireShared(int arg):共享式擷取同步狀态,傳回值大于等于0則表示擷取成功,否則擷取失敗;
  7. tryReleaseShared(int arg):共享式釋放同步狀态;
  8. isHeldExclusively():目前同步器是否在獨占式模式下被線程占用,一般該方法表示是否被目前線程所獨占;
  9. acquire(int arg):獨占式擷取同步狀态,如果目前線程擷取同步狀态成功,則由該方法傳回,否則,将會進入同步隊列等待,該方法将會調用可重寫的tryAcquire(int arg)方法;
  10. acquireInterruptibly(int arg):與acquire(int arg)相同,但是該方法響應中斷,目前線程為擷取到同步狀态而進入到同步隊列中,如果目前線程被中斷,則該方法會抛出InterruptedException異常并傳回;
  11. tryAcquireNanos(int arg,long nanos):逾時擷取同步狀态,如果目前線程在nanos時間内沒有擷取到同步狀态,那麼将會傳回false,已經擷取則傳回true;
  12. acquireShared(int arg):共享式擷取同步狀态,如果目前線程未擷取到同步狀态,将會進入同步隊列等待,與獨占式的主要差別是在同一時刻可以有多個線程擷取到同步狀态;
  13. acquireSharedInterruptibly(int arg):共享式擷取同步狀态,響應中斷;
  14. tryAcquireSharedNanos(int arg, long nanosTimeout):共享式擷取同步狀态,增加逾時限制;
  15. release(int arg):獨占式釋放同步狀态,該方法會在釋放同步狀态之後,将同步隊列中第一個節點包含的線程喚醒;
  16. releaseShared(int arg):共享式釋放同步狀态;

後面LZ将會就CLH隊列,同步狀态的擷取、釋放做詳細介紹。

- END -

 往期推薦:

  • 死磕Java系列:
  1. 深入分析ThreadLocal

  2. 深入分析synchronized的實作原理

  3. 深入分析volatile的實作原理

  4. Java記憶體模型之happens-before

  5. Java記憶體模型之重排序

  6. Java記憶體模型之分析volatile

  7. Java記憶體模型之總結

……

  • Spring系列:
  1. Spring Cloud Zuul中使用Swagger彙總API接口文檔

  2. Spring Cloud Config Server遷移節點或容器化帶來的問題

  3. Spring Cloud Config對特殊字元加密的處理

  4. Spring Boot使用@Async實作異步調用:使用Future以及定義逾時

  5. Spring Cloud建構微服務架構:分布式配置中心(加密解密)

  6. Spring Boot快速開發利器:Spring Boot CLI

号外:

最近在做幾個有意思的開源項目,感興趣的朋友可以看看。

位址:

https://github.com/dyc87112/swagger-butler

可關注我的公衆号

深入交流、更多福利

掃碼加入我的知識星球

AQS
下一篇: JUC學習指南

繼續閱讀