1. 程式人生 > >【死磕Java併發】-----J.U.C之AQS:AQS簡介

【死磕Java併發】-----J.U.C之AQS: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主要提供瞭如下一些方法:

  • 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佇列,同步狀態的獲取、釋放做詳細介紹

參考資料

  1. Doug Lea:《Java併發程式設計實戰》
  2. 方騰飛:《Java併發程式設計的藝術》

歡迎掃一掃我的公眾號關注 — 及時得到部落格訂閱哦!

–— Java成神之路: 488391811(一起走向Java成神) –—
這裡寫圖片描述