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主要提供了如下一些方法:
- getState():傳回同步狀态的目前值;
- setState(int newState):設定目前同步狀态;
- compareAndSetState(int expect, int update):使用CAS設定目前狀态,該方法能夠保證狀态設定的原子性;
- tryAcquire(int arg):獨占式擷取同步狀态,擷取同步狀态成功後,其他線程需要等待該線程釋放同步狀态才能擷取同步狀态;
- tryRelease(int arg):獨占式釋放同步狀态;
- tryAcquireShared(int arg):共享式擷取同步狀态,傳回值大于等于0則表示擷取成功,否則擷取失敗;
- tryReleaseShared(int arg):共享式釋放同步狀态;
- isHeldExclusively():目前同步器是否在獨占式模式下被線程占用,一般該方法表示是否被目前線程所獨占;
- acquire(int arg):獨占式擷取同步狀态,如果目前線程擷取同步狀态成功,則由該方法傳回,否則,将會進入同步隊列等待,該方法将會調用可重寫的tryAcquire(int arg)方法;
- acquireInterruptibly(int arg):與acquire(int arg)相同,但是該方法響應中斷,目前線程為擷取到同步狀态而進入到同步隊列中,如果目前線程被中斷,則該方法會抛出InterruptedException異常并傳回;
- tryAcquireNanos(int arg,long nanos):逾時擷取同步狀态,如果目前線程在nanos時間内沒有擷取到同步狀态,那麼将會傳回false,已經擷取則傳回true;
- acquireShared(int arg):共享式擷取同步狀态,如果目前線程未擷取到同步狀态,将會進入同步隊列等待,與獨占式的主要差別是在同一時刻可以有多個線程擷取到同步狀态;
- acquireSharedInterruptibly(int arg):共享式擷取同步狀态,響應中斷;
- tryAcquireSharedNanos(int arg, long nanosTimeout):共享式擷取同步狀态,增加逾時限制;
- release(int arg):獨占式釋放同步狀态,該方法會在釋放同步狀态之後,将同步隊列中第一個節點包含的線程喚醒;
- releaseShared(int arg):共享式釋放同步狀态;
後面LZ将會就CLH隊列,同步狀态的擷取、釋放做詳細介紹。
- END -
往期推薦:
- 死磕Java系列:
-
深入分析ThreadLocal
-
深入分析synchronized的實作原理
-
深入分析volatile的實作原理
-
Java記憶體模型之happens-before
-
Java記憶體模型之重排序
-
Java記憶體模型之分析volatile
-
Java記憶體模型之總結
……
- Spring系列:
-
Spring Cloud Zuul中使用Swagger彙總API接口文檔
-
Spring Cloud Config Server遷移節點或容器化帶來的問題
-
Spring Cloud Config對特殊字元加密的處理
-
Spring Boot使用@Async實作異步調用:使用Future以及定義逾時
-
Spring Cloud建構微服務架構:分布式配置中心(加密解密)
-
Spring Boot快速開發利器:Spring Boot CLI
号外:
最近在做幾個有意思的開源項目,感興趣的朋友可以看看。
位址:
https://github.com/dyc87112/swagger-butler
可關注我的公衆号
深入交流、更多福利
掃碼加入我的知識星球