aqs內部維護著乙個fifo的佇列,即clh佇列。aqs的同步機制就是依靠clh佇列實現的。clh佇列是fifo的雙端雙向佇列,實現公平鎖。執行緒通過aqs獲取鎖失敗,就會將執行緒封裝成乙個node節點,插入佇列尾。當有執行緒釋放鎖時,後嘗試把隊頭的next節點占用鎖。
clh佇列結構
clh佇列由node物件組成,node是aqs中的內部類。
重要屬性
//用於標識共享鎖
static final node shared = new node();
//用於標識獨佔鎖
static final node exclusive = null;
/*** 因為超時或者中斷,節點會被設定為取消狀態,被取消的節點時不會參與到競爭中的,他會一直保持取消狀態不會轉變為其他狀態;
*/static final int cancelled = 1;
/*** 當前節點釋放鎖的時候,需要喚醒下乙個節點
*/static final int signal = -1;
/*** 節點在等待佇列中,節點執行緒等待condition喚醒
*/static final int condition = -2;
/*** 表示下一次共享式同步狀態獲取將會無條件地傳播下去
*/static final int propagate = -3;
/** 等待狀態 */
volatile int waitstatus;
/** 前驅節點 */
volatile node prev;
/** 後繼節點 */
volatile node next;
/** 節點執行緒 */
volatile thread thread;
//node nextwaiter;
clh佇列執行
執行緒呼叫acquire方法獲取鎖,如果獲取失敗則會進入clh佇列
public final void acquire(int arg)
2.addwaiter(node.exclusive)方法會將當前執行緒封裝成node節點,追加在隊尾。
private node addwaiter(node mode)
}//前面cas更新失敗後,再enq方法中迴圈用cas更新直到成功
enq(node);
return node;
}
acquirequeued方法中會使執行緒自旋阻塞,直到獲取到鎖。
final boolean acquirequeued(final node node, int arg)
/**更改當前節點前置節點的waitstatus,只有前置節點的waitstatus=node.signal,當前節點才有可能被喚醒。如果前置節點的waitstatus>0(即取消),則跳過取更前面的節點。
*/if (shouldparkafte***iledacquire(p, node) &&
//通過unsafe.park來阻塞執行緒
parkandcheckinterrupt())
interrupted = true;
}} finally
}
執行緒釋放鎖,從前面可以知道,獲取到鎖的執行緒會設定為clh佇列的頭部。這裡如果tryrelease返回true,且head的waitstatus!=0。就會更新head的waitstatus為0並且 喚醒執行緒head.next節點的執行緒。
public final boolean release(int arg)
return false;
}
更新head的waitstatus為0並且喚醒執行緒head.next節點的執行緒
private void unparksuccessor(node node)
是呼叫了unsafe.unpark,喚醒執行緒。
if (s != null)
locksupport.unpark(s.thread);
}
併發程式設計之AQS中的CLH佇列
在aqs類檔案的開頭,作者新增了很長一段注釋,向開發者解釋clh佇列,以及aqs對clh佇列的使用。aqs裡面的clh佇列是clh同步鎖的一種變形。其主要從兩方面進行了改造 節點的結構與節點等待機制。在結構上,aqs類引入了頭結點和尾節點,他們分別指向佇列的頭和尾,嘗試獲取鎖 入佇列 釋放鎖等實現都...
JUC併發基石之AQS原始碼解析 獨佔鎖的釋放
juc併發基石之aqs原始碼解析 獨佔鎖的獲取public final boolean release int arg return false 獨佔鎖的涉及到兩個函式的呼叫 1.tryrelease arg 該方法由aqs的子類來實現釋放鎖的具體邏輯 2.unparksuccessor h 喚醒後...
Java之 AQS在幾個同步工具類中的使用
工具類 工具類作用 工具類加鎖方法 工具類釋放鎖方法 sync覆蓋的方法 sync非覆蓋的重要方法 state的作用 鎖型別鎖維護 semaphore 控制同時訪問某個特定資源的運算元量 acquire 每次請求乙個許可都會導致計數器減少1,一旦達到了0,新的許可請求執行緒將被掛起 release ...