背景:
AbstractQueuedSynchronizer(AQS)
public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer implements java.io.Serializable
-
介紹
- 提供一個框架,用於實現依賴先進先出(FIFO)等待隊列的阻塞鎖和相關同步器(信號量,事件等)。 該類被設計爲大多數類型的同步器的有用依據,這些同步器依賴於單個原子
int
值來表示狀態。 子類必須定義改變此狀態的受保護方法,以及根據該對象被獲取或釋放來定義該狀態的含義。 給定這些,這個類中的其他方法執行所有排隊和阻塞機制。 子類可以保持其他狀態字段,但只以原子方式更新int
使用方法操縱值getState
()
,setState(int)
和compareAndSetState(int, int)
被跟蹤相對於同步。 - 子類應定義爲非公共內部助手類,用於實現其封閉類的同步屬性。
AbstractQueuedSynchronizer
類不實現任何同步接口。 相反,它定義了一些方法,如acquireInterruptibly(int)
,可以通過具體的鎖和相關同步器來調用適當履行其公共方法。 - 此類支持默認獨佔模式和共享模式。【使用模板模式來定義是獨佔還是共享模式】 當以獨佔模式獲取時,嘗試通過其他線程獲取不能成功。 多線程獲取的共享模式可能(但不需要)成功。 除了在機械意義上,這個類不理解這些差異,當共享模式獲取成功時,下一個等待線程(如果存在)也必須確定它是否也可以獲取。 在不同模式下等待的線程共享相同的FIFO隊列。 通常,實現子類只支持這些模式之一,但是兩者都可以在
ReadWriteLock
中發揮作用 。 僅支持獨佔或僅共享模式的子類不需要定義支持未使用模式的方法。 - 這個類定義的嵌套
AbstractQueuedSynchronizer
.
ConditionObject
可用於作爲一類Condition
由子類支持獨佔模式用於該方法的實施isHeldExclusively()
份報告是否同步排他相對於保持在當前線程,方法release(int)
與當前調用getState()
值完全釋放此目的,和acquire(int)
,給定此保存的狀態值,最終將此對象恢復到其先前獲取的狀態。AbstractQueuedSynchronizer
方法將創建此類條件,因此如果不能滿足此約束,請勿使用該約束。AbstractQueuedSynchronizer.ConditionObject
的行爲當然取決於其同步器實現的語義。 - 該類爲內部隊列提供檢查,檢測和監控方法,以及條件對象的類似方法。 這些可以根據需要導出到類中,使用
AbstractQueuedSynchronizer
進行同步機制。 - 此類的序列化僅存儲底層原子整數維持狀態,因此反序列化對象具有空線程隊列。 需要可序列化的典型子類將定義一個
readObject
方法,可以將其恢復爲readObject
時的已知初始狀態。
-
用法
使用這個類用作同步的基礎上,重新定義以下方法,【即在同步器中定義內部類重寫下面的方法】,如適用,通過檢查和/或修改使用所述同步狀態
getState()
,setState(int)
或compareAndSetState(int,
int)【通過這三個方法來保證原子性和線程安全性】
:tryAcquire(int)獨佔模式獲取鎖
tryRelease(int)獨佔模式釋放鎖
tryAcquireShared(int)共享模式獲取鎖
tryReleaseShared(int)共享模式釋放鎖
isHeldExclusively()是否是獨佔式
UnsupportedOperationException
。 這些方法的實現必須是線程安全的,通常應該是短的而不是阻止的。 定義這些方法是唯一支持使用此類的方法。 所有其他方法都被聲明爲final
,因爲它們不能獨立變化。 -
看下面的源碼分析前可先觀看多線程高併發編程(2) -- 可重入鎖介紹和自定義
一.ReentrantLock的lock和unlock源碼解析
-
lock流程:
- 調用同步器Sync的抽象方法lock,由公平鎖FairSync實現
- 調用AQS的acquire獲取鎖
- 嘗試獲取鎖:公平鎖FairSync的tryAcquire
- 第一次獲取鎖,若隊列沒有前節點和設置狀態成功,存儲當前線程,返回true,表示獲取成功;
- 如果是重入獲取,鎖持有數量+1;
- 獲取鎖失敗,把當前線程加入等待隊列中,並對等待隊列進行阻塞,不斷競爭獲取鎖:acquireQueued遍歷等待隊列addWaiter,若有頭節點則從隊列中取出來,若沒有則進行中斷;
- 嘗試獲取鎖:公平鎖FairSync的tryAcquire
-
unlock流程:
- 調用同步器的release方法,有AQS實現;
- tryRelease釋放鎖,由Sync實現
- 鎖數量-1;
- 當前線程和保存的線程不一致拋出異常;
- 鎖數量爲0則進行釋放鎖,把獨佔線程設置爲null,修改狀態;
1 //===========================ReentrantLock源碼=============================== 2 public class ReentrantLock implements Lock, java.io.Serializable { 3 private final Sync sync;//同步器 4 public void lock() {//獲取鎖 5 sync.lock();//調用同步器Sync的lock,由FairSync實現 6 } 7 public void unlock() {//使用鎖 8 sync.release(1);//調用同步器的release,由AQS實現 9 } 10 11 12 //內部類,同步器繼承AQS,實現tryRelease釋放鎖 13 abstract static class Sync extends AbstractQueuedSynchronizer{ 14 abstract void lock();//獲取鎖抽象方法,由FairSync實現 15 //===========================釋放鎖=============================== 16 protected final boolean tryRelease(int releases) { 17 int c = getState() - releases;//鎖數量-1 18 //當前線程和保存的線程不一致 19 if (Thread.currentThread() != getExclusiveOwnerThread()) 20 throw new IllegalMonitorStateException(); 21 boolean free = false; 22 if (c == 0) {//持有的鎖數量爲0 23 free = true;//釋放鎖 24 setExclusiveOwnerThread(null);//當前獨佔線程爲null 25 } 26 setState(c);//設置狀態 27 return free; 28 } 29 } 30 31 //內部類,公平鎖繼承同步器,實現lock方法 32 static final class FairSync extends Sync { 33 //===========================獲取鎖=============================== 34 final void lock() { 35 acquire(1);//調用AQS的acquire 36 } 37 protected final boolean tryAcquire(int acquires) { 38 final Thread current = Thread.currentThread();//獲得當前線程 39 /**getState是AQS的Node的waitStatus,其值有 40 *CANCELLED = 1 41 *SIGNAL = -1 42 *CONDITION = -2 43 *PROPAGATE = -3 44 */ 45 int c = getState(); 46 //c初始值爲0,0表示不是以上的狀態;hasQueuedPredecessors之前是否有節點, 47 //如果是true表示這個線程的前面還有節點應該讓前面的節點先獲取鎖,當前線程獲取失敗; 48 //【非公平鎖少了hasQueuedPredecessors這個判斷】 49 //compareAndSetState CAS比較,設置當前狀態爲1;setExclusiveOwnerThread當前線程設置爲獨佔線程 50 if (c == 0) { 51 if (!hasQueuedPredecessors() && 52 compareAndSetState(0, acquires)) { 53 setExclusiveOwnerThread(current); 54 return true;//獲取成功 55 } 56 } 57 else if (current == getExclusiveOwnerThread()) {//如果是當前線程,表示重入 58 int nextc = c + acquires;//鎖數量+1 59 if (nextc < 0)//小於0表示溢出 60 throw new Error("Maximum lock count exceeded"); 61 setState(nextc);//更新狀態 62 return true;//獲取成功 63 } 64 return false;//獲取失敗 65 } 66 } 67 } 68 69 70 71 //=============AbstractQueuedSynchronizer源碼============== 72 public abstract class AbstractQueuedSynchronizer 73 extends AbstractOwnableSynchronizer 74 implements java.io.Serializable{ 75 //===========================獲取鎖=============================== 76 //以獨佔模式獲取,忽略中斷。通過調用至少一次tryAcquire(int)實現,成功返回。否則線程排隊, 77 //可能會重複阻塞和解除阻塞,直到成功才調用tryAcquire(int)。 78 public final void acquire(int arg) {//FairSync的lock調用 79 //tryAcquire獲取鎖;acquireQueued線程加入到了等待隊列中,進行阻塞等待,競爭獲取鎖; 80 //addWaiter其他線程獲取鎖失敗添加到等待隊列中;Node.EXCLUSIVE節點獨佔,爲null 81 if (!tryAcquire(arg) && 82 acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) 83 selfInterrupt(); 84 } 85 protected boolean tryAcquire(int arg) {//acquire調用,由FairSync實現 86 throw new UnsupportedOperationException(); 87 } 88 final boolean acquireQueued(final Node node, int arg) {//acquire調用 89 boolean failed = true; 90 try { 91 boolean interrupted = false; 92 for (;;) { 93 final Node p = node.predecessor();//獲取前一個節點 94 if (p == head && tryAcquire(arg)) {//如果獲取的節點爲頭節點並且獲取到鎖 95 setHead(node);//當前節點設置爲頭節點 96 p.next = null;//頭節點下一節點爲空,即把當前節點從隊列中移除出來 97 failed = false; 98 return interrupted; 99 } 100 //當前節點不是頭節點,parkAndCheckInterrupt讓當前線程處於阻塞等待狀態由其他線程喚醒 101 if (shouldParkAfterFailedAcquire(p, node) && 102 parkAndCheckInterrupt()) 103 interrupted = true; 104 } 105 } finally { 106 if (failed) 107 cancelAcquire(node); 108 } 109 } 110 private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {//acquireQueued調用 111 int ws = pred.waitStatus;//獲取前一節點的等待狀態 112 if (ws == Node.SIGNAL)//如果狀態爲喚醒狀態 113 return true; 114 if (ws > 0) {//處於CANCELLED狀態 115 do { 116 node.prev = pred = pred.prev;//1.把所有處於CANCELLED狀態的節點移除 117 } while (pred.waitStatus > 0); 118 pred.next = node;//2.把所有處於CANCELLED狀態的節點移除 119 } else { 120 compareAndSetWaitStatus(pred, ws, Node.SIGNAL);//設置爲SIGNAL狀態 121 } 122 return false; 123 } 124 private Node addWaiter(Node mode) {//acquireQueued的參數,在acquire中調用 125 Node node = new Node(Thread.currentThread(), mode);//創建Node,當前線程指向node 126 Node pred = tail;//前節點指向尾節點【雙向鏈表】 127 if (pred != null) {//尾節點不爲空 128 node.prev = pred;//當前線程節點指向尾節點 129 if (compareAndSetTail(pred, node)) {//CAS比較,把當前線程節點更新爲尾節點 130 pred.next = node;//前尾節點的下一節點指向當前尾節點 131 return node; 132 } 133 } 134 enq(node);//如果尾節點爲空,把當前節點放到一個初始化節點或添加到節點中做爲尾節點 135 return node; 136 } 137 private Node enq(final Node node) {//addWaiter調用 138 for (;;) { 139 Node t = tail; 140 if (t == null) { // 尾節點爲空 141 if (compareAndSetHead(new Node()))//創建新節點並維護一個頭節點 142 tail = head;//把當前節點設置爲頭節點 143 } else { 144 node.prev = t;//當前節點指向尾節點 145 if (compareAndSetTail(t, node)) {//把當前節點更新爲尾節點 146 t.next = node;//前尾節點的下一節點指向當前尾節點 147 return t; 148 } 149 } 150 } 151 } 152 static void selfInterrupt() {//acquire調用 153 Thread.currentThread().interrupt();//當前線程中斷 154 } 155 //===========================釋放鎖=============================== 156 public final boolean release(int arg) {//ReentrantLock的unlock調用 157 if (tryRelease(arg)) {//當前線程鎖釋放成功,喚醒其他線程進行資源的競爭 158 Node h = head; 159 if (h != null && h.waitStatus != 0) 160 unparkSuccessor(h); 161 return true; 162 } 163 return false; 164 } 165 protected boolean tryRelease(int arg) {//release調用,由Sync實現 166 throw new UnsupportedOperationException(); 167 } 168 }
備註:公平鎖是針對鎖的獲取而言,如果一個鎖是公平的,那麼鎖的獲取順序就應該符合請求的絕對時間順序;非公平鎖會進行插隊獲取鎖;
二.AQS重寫鎖
流程:
- 實現Lock,重寫實現方法lock、lockInterruptibly、tryLock、unlock、newCondition;
- 內部類繼承AQS,重寫tryAcquire和tryRelease;
1 public class MyAQSLock implements Lock{ 2 private MyAQS myAQS; 3 private class MyAQS extends AbstractQueuedSynchronizer{ 4 @Override 5 protected boolean tryAcquire(int arg) { 6 int state = getState();//獲取狀態 7 Thread thread = Thread.currentThread(); 8 if(state==0){//線程第一次進來獲取,狀態爲0,表示可以拿到鎖 9 if(compareAndSetState(0,arg)){//更新狀態 10 setExclusiveOwnerThread(Thread.currentThread());//設置爲獨佔線程,其他線程進來進入等待 11 return true;//獲取成功 12 } 13 }else if(getExclusiveOwnerThread()== thread){//重入,存儲線程等於當前線程 14 setState(state+1);//鎖數量+1 15 return true; 16 } 17 return false;//獲取失敗 18 } 19 20 @Override 21 protected boolean tryRelease(int arg) { 22 //當前線程不是存儲線程 23 if(Thread.currentThread() != getExclusiveOwnerThread()){ 24 throw new RuntimeException(); 25 } 26 int state = getState()-arg;//鎖數量-1 27 boolean flag = false; 28 if(state==0){//鎖數量爲0 29 setExclusiveOwnerThread(null);//獨佔鎖爲null,表示可以讓其他線程進來競爭獲取資源了 30 flag=true; 31 } 32 setState(state);//更新狀態 33 return flag; 34 } 35 36 public ConditionObject newConditonObject(){ 37 return new ConditionObject(); 38 } 39 } 40 @Override 41 public void lock() { 42 myAQS.acquire(1); 43 } 44 45 @Override 46 public void lockInterruptibly() throws InterruptedException { 47 myAQS.acquireInterruptibly(1); 48 } 49 50 @Override 51 public boolean tryLock() { 52 return myAQS.tryAcquire(1); 53 } 54 55 @Override 56 public boolean tryLock(long time, TimeUnit unit) throws InterruptedException { 57 return myAQS.tryAcquireNanos(1,unit.toNanos(time)); 58 } 59 60 @Override 61 public void unlock() { 62 myAQS.release(1); 63 } 64 65 @Override 66 public Condition newCondition() { 67 return myAQS.newConditonObject(); 68 } 69 }