1. 程式人生 > >Java併發程式設計之AQS

Java併發程式設計之AQS

一、什麼是AQS

  AQS(AbstractQueuedSynchronize:佇列同步器)是用來構建鎖或者其他同步元件的基礎框架,很多同步類都是在它的基礎上實現的,比如常用的ReentrantLock、ReentrantReadWriteLock、CountDownLatch、Semaphore。

 

二、實現原理

  在AQS內部,定義了一個 volatile int state 變數來標識同步狀態,通過改變state的狀態來控制對共享資源的訪問,根據不同的實現,state可以表示不同的狀態,例如:在 ReentrantLock 中它表示擁有該鎖的執行緒請求了多少次該鎖;在 Semaphore 中表示

剩餘的許可數,在 FutureTask 中表示任務的狀態(尚未開始、執行、完成和取消)。同時定義了一個 FIFO 佇列維護爭用資源時被阻塞的執行緒,當執行緒嘗試獲取鎖時,如果鎖已經被佔用,那麼該執行緒就會被構造成一個Node節點放到同步佇列的尾部;佇列的頭節點是成功獲取鎖的節點,當頭節點執行緒釋放鎖時,會喚醒後面的節點並釋放當前頭節點的引用。AQS主要通過繼承的方式來使用,子類通過繼承AQS並實現它的抽象方法來定義state變數的具體的訪問規則,從而可以實現不同型別的同步元件。AQS自身沒有實現任何同步介面,為了保證對state的訪問修改操作是安全的,AQS提供了以下三個方法供自定義同步元件使用:

  1. getState():獲取當前同步狀態。
  2. setState(int newState):設定當前同步狀態。
  3. compareAndSetState(int expect,int update):使用CAS設定當前狀態,該方法能夠保證狀態設定的原子性。

  AQS是實現鎖的關鍵,它在底層對同步狀態管理、執行緒的排隊、等待與喚醒做了實現,簡化鎖的實現。

  AQS定義了兩種資源共享的方式:獨佔式和共享式。

  1. 獨佔式:同時只有一個執行緒能訪問該共享資源。
  2. 共享式:多個執行緒可以同時訪問該共享資源。

  AQS是基於模板方法模式設計的,它提供了一些模板方法,自定義同步器時重寫這些方法。這些模板方法如下:

  1. protected boolean tryAcquire(int arg):獨佔式獲取同步狀態,成功則返回true,失敗則返回false。先查詢同步狀態並判斷同步狀態是否符合預期,然後再進行CAS設定同步狀態。
  2. protected boolean tryRelease(int arg):獨佔式釋放同步狀態,成功則返回true,失敗則返回false。等待獲取同步狀態的執行緒將有機會獲取同步狀態。
  3. protected int tryAcquireShared(int arg):共享式獲取同步狀態,返回大於等於0的值,表示成功,該值表示剩餘可用資源數,小於0則表示獲取失敗。
  4. protected boolean tryReleaseShared(int arg):共享式釋放同步狀態,如果釋放後允許喚醒後續等待結點返回true,否則返回false。
  5. protected boolean isHeldExclusively():當前同步器是否在獨佔模式下被執行緒佔用,只在 AbstractQueuedSynchronizer.ConditionObject 方法內進行內部呼叫,不使用Condition可以不實現。