AbstractQueuedSynchronizer抽象類-阻塞鎖

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釋放鎖,其他線程才能修改成功,獲取到鎖。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章