AbstractQueuedSynchronizer抽象類-阻塞鎖
AbstractQueuedSynchronizer 是多線程情況下保證代碼快有序運行的一種設計,對多線程獲取鎖進行了抽象,
設計中包括:
1.線程隊列(阻塞的線程)
當很多線程競爭鎖的時候,排隊一個個獲取鎖,先進先出
2.線程獲取鎖,成功就執行後面的代碼
3.線程釋放鎖,如果等待隊列中有線程,喚醒隊列中的線程
關鍵方法有
addWaiter 添加阻塞線程到隊列
acquire 獲取鎖,
release 釋放鎖。
線程等待隊列
線程隊列結構
隊列是雙向鏈表,通過prev(前) 和 next (後)連接,
整個隊列有兩個初始變量,head 與 tail分別代表隊列的頭部和尾巴。喚醒線程就是通過prev尋找最前面的節點,添加阻塞線程就是通過.next加到尾部,先進先出的處理邏輯。
獲取鎖
acquire是一個獲取鎖的模板方法,邏輯字面上可以理解
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
protected boolean tryAcquire(int arg) {
throw new UnsupportedOperationException(); //拋出異常
}
1 tryAcquire 嘗試獲取鎖
2 addWaiter 獲取鎖失敗,當前線程信息(自己)放入隊列
3 acquireQueued 放入隊列後,阻塞自己,等待其他線程釋放鎖後喚醒(自己)
tryAcquire 方法是拋出異常,是要我們自己寫具體邏輯的,實現不同類型的個性化鎖,ReentranLock類內部有實現邏輯的列子。
獲取鎖失敗-放入隊列
addWaiter方法是將創建一個節點,並且這個節點包含當前線程信息,整個是一個鏈表結構的隊列。
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode); //1
Node pred = tail;
if (pred != null) {
node.prev = pred; //2
if (compareAndSetTail(pred, node)) {
pred.next = node; //3
return node;
}
}
enq(node);
return node;
}
//在每次創建一個node節點的時候, 將尾部更新,
//node.prev = pred; 設置前一個節點
//compareAndSetTail(pred, node) 更新尾巴爲新加如的節點(自己)
//pred.next = node; 尾巴的next更新
1 通過上面的代碼能知道大致思想是,創建一個攜帶當前線程信息的node,
2 如果隊列的尾部tail不爲空,node的前節點設置爲pred,Node pred = tail; node.prev = pred;
3 並且更新一下鏈表尾部,compareAndSetTail
實際的效果就是 tail = node; 更新尾部節點。
釋放鎖
release 與 acquire對應,是將鎖釋放,並且在鎖釋放之後,喚醒隊列頭部的線程
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h); //喚醒線程
return true;
}
return false;
}
protected boolean tryRelease(int arg) {
throw new UnsupportedOperationException(); //拋出異常
}
喚醒線程
unparkSuccessor
private void unparkSuccessor(Node node) {
int ws = node.waitStatus;
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);
Node s = node.next;
if (s == null || s.waitStatus > 0) {
s = null;
for (Node t = tail; t != null && t != node; t = t.prev) //循環獲取,找到隊列裏最前面的節點
if (t.waitStatus <= 0)
s = t;
}
if (s != null)
LockSupport.unpark(s.thread); //喚醒隊列中的線程
}
CAS原子操作數
CAS 指的是 compareAndSwap 比較並交換技術,
private volatile int state;
protected final int getState() {
return state;
}
protected final void setState(int newState) {
state = newState;
}
protected final boolean compareAndSetState(int expect, int update) {
// See below for intrinsics setup to support this
return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
簡言之,類中state變量,對他的操作時,傳入兩個值,分別是期望原值,更新值,如果期望原值==原值,才能更新成功,否則更新失敗,
線程Thread1 調用 compareAndSetState(0,1) 如果成功,state的值將變爲1,其他線程compareAndSetState(0,1)都會失敗,因爲其他線程期望原值 state = 0, 實際 state值已經被Thread1 線程修改爲1。需要Thread1 執行完代碼塊之後,將state值改回0釋放鎖,其他線程才能修改成功,獲取到鎖。