Java 抽象同步隊列 AbstractQueuedSynchronizer

目錄

1. AbstractQueuedSynchronizer 介紹

2. AQS 內部結構

3. 狀態信息 state

4. 內部類 Node

4.1 Node 類源碼

4.2 對 Node 的 CAS 操作

4.3 隊列中的 Node 操作

5. 內部類 ConditionObject

5.1 await() 方法

5.2 signal() 方法

6. 獲取和釋放資源的方法

6.1 獨享方式

6.2 共享方式


1. AbstractQueuedSynchronizer 介紹

抽象同步隊列 AbstractQueuedSynchronizer ,簡稱 AQS,它是實現阻塞鎖和其他基於先入先出(FIFO)等待隊列的同步組件。

併發包中鎖的底層實現(如 ReentrantLock )的底層實現就是使用 AQS 實現的。

 

2. AQS 內部結構

i. AQS 繼承自 AbstractOwnableSynchronizer

ii. 類 ConditionObject 主要提供一種條件,由子類決定是否支持獨佔模式

iii. 類 Node,作爲先入先出(FIFO)阻塞隊列裏面的每個節點

 

3. 狀態信息 state

AQS 維持了一個單一的狀態信息 state,可通過 getState()、setState(int newState)、compareAndSetState(int expect, int update) 方法來修改 state 的值。

private static final Unsafe unsafe = Unsafe.getUnsafe();
// 狀態信息
private volatile int state;
// 返回當前的狀態值。該操作擁有 volatile 讀的內存語義
protected final int getState() {
    return state;
}
//設置狀態值
protected final void setState(int newState) {
    state = newState;
}
// 通過 unsafe 類原子的設置同步狀態值爲給定的 update 值,設置成功後返回true,否則返回false
protected final boolean compareAndSetState(int expect, int update) {
    return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}

state 作用舉例:

ReentrantLock 中,state 表示當前線程獲取鎖的可重入次數。

ReentrantReadWriteLock 中,state 高 16 位表示獲取讀鎖的次數,低 16 爲表示獲取寫鎖的線程的可重入次數。

 

4. 內部類 Node

4.1 Node 類源碼

static final class Node {
    // 標記符,共享模式下的等待節點
    static final Node SHARED = new Node();
    // 標記符,獨佔模式下等待節點
    static final Node EXCLUSIVE = null;
    
    /**
      * 等待狀態值
      *   1 表示線程已經被取消
      * -1 表示一個後繼節點的線程需要喚醒
      * -2 表示線程等待在某種條件下
      * -3 表示下一次共享式獲取狀態的操作應該無條件的傳播
      */
    static final int CANCELLED =  1;
    static final int SIGNAL    = -1;
    static final int CONDITION = -2;
    static final int PROPAGATE = -3;

   // 狀態字段,取上述 4 個狀態值。值爲 0,表示非以上狀態
    volatile int waitStatus;
    // 當前節點的前驅節點
    volatile Node prev;
    // 當前節點的後繼節點
    volatile Node next;
    // 節點關聯的線程
    volatile Thread thread;
    // 下一個處於等待條件的節點
    Node nextWaiter;

    // 判斷節點是否以共享模式等待
    final boolean isShared(){
        return nextWaiter == SHARED;
    }
    // 如果有前驅節點,則返回該節點
    final Node predecessor() throws NullPointerException {
        Node p = prev;
        if (p == null)
            throw new NullPointerException();
        else
            return p;
    }
    Node() { 
    }
    // addWaiter 使用。給線程添加等待模型
    Node(Thread thread, Node mode) {
        this.nextWaiter = mode;
        this.thread = thread;
    }
    // Condition 使用,給線程添加等待條件
    Node(Thread thread, int waitStatus) {
        this.waitStatus = waitStatus;
        this.thread = thread;
    }
}

4.2 對 Node 的 CAS 操作

private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long stateOffset;
private static final long headOffset;
private static final long tailOffset;
private static final long waitStatusOffset;
private static final long nextOffset;

static {
    try {
        stateOffset = unsafe.objectFieldOffset
            (AbstractQueuedSynchronizer.class.getDeclaredField("state"));
        headOffset = unsafe.objectFieldOffset
            (AbstractQueuedSynchronizer.class.getDeclaredField("head"));
        tailOffset = unsafe.objectFieldOffset
            (AbstractQueuedSynchronizer.class.getDeclaredField("tail"));
        waitStatusOffset = unsafe.objectFieldOffset
            (Node.class.getDeclaredField("waitStatus"));
        nextOffset = unsafe.objectFieldOffset
            (Node.class.getDeclaredField("next"));

    } catch (Exception ex) { throw new Error(ex); }
}

/**
 * 使用 unsafe 類對 Node 進行原子更新。如果當前狀態值等於預期值,則以原子方式將同步狀態設置爲給定的更新值。
 */
private final boolean compareAndSetHead(Node update) {
    return unsafe.compareAndSwapObject(this, headOffset, null, update);
}

private final boolean compareAndSetTail(Node expect, Node update) {
    return unsafe.compareAndSwapObject(this, tailOffset, expect, update);
}
private static final boolean compareAndSetWaitStatus(Node node,
                                                        int expect,
                                                        int update) {
    return unsafe.compareAndSwapInt(node, waitStatusOffset,
                                    expect, update);
}
private static final boolean compareAndSetNext(Node node,
                                                Node expect,
                                                Node update) {
    return unsafe.compareAndSwapObject(node, nextOffset, expect, update);
}

4.3 隊列中的 Node 操作

/**
* 將節點加入隊列,必要時進行初始化
*/
private Node enq(final Node node) {
    for (;;) {
        Node t = tail;
        if (t == null) {
            // 尾結點爲空,需要初始化
            if (compareAndSetHead(new Node()))
                tail = head;
        } else {
            // 尾結點不爲空,unsafe進行插入節點
            node.prev = t;
            if (compareAndSetTail(t, node)) {
                t.next = node;
                return t;
            }
        }
    }
}
/**
 * 爲當前線程設置指定模式。並加入隊列
 */
private Node addWaiter(Node mode) {
    Node node = new Node(Thread.currentThread(), mode);
    Node pred = tail;
    if (pred != null) {
        node.prev = pred;
        if (compareAndSetTail(pred, node)) {
            pred.next = node;
            return node;
        }
    }
    enq(node);
    return node;
}
/**
 * 設置頭結點
 */
private void setHead(Node node) {
    head = node;
    node.thread = null;
    node.prev = null;
}
/**
 * 如果存在後繼節點則進行喚醒操作
 */
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);
}

 

5. 內部類 ConditionObject

ConditionObject 實現了 Condition 接口。Condition 對象是由 Lock 對象創建的。

/** 
 * 等待隊列中的頭結點
 */
private transient Node firstWaiter;
/** 
 * 等待隊列中的尾結點
 */
private transient Node lastWaiter;

ConditionObject 核心的兩個方法:await() 、signal()

5.1 await() 方法

  • 當前線程進入等待狀態,直到被通知(signal)或中斷
  • 當前線程將進入運行狀態且從 await() 方法返回的情況:
    • 其他線程調用該 Condition 的 signal() 或 signalAll() 方法
    • 其他線程調用 interrupt() 方法中斷當前線程
    • 如果等待線程從 await() 方法返回,則該線程已經獲取了 Condition 對象所對應的鎖

5.2 signal() 方法

喚醒一個等待在 Condition 上的線程,該線程從等待方法返回前必須獲得與 Condition 相關聯的鎖

signal() 爲喚醒一個線程,signalAll() 爲喚醒所有等待的線程

 

6. 獲取和釋放資源的方法

獨享方式:acquire(int arg)、acquireInterruptibly(int arg)、release(int arg)

共享方式:acquireShared(int arg) 、acquireSharedInterruptibly(int arg)、releaseShared(int arg) 

6.1 獨享方式

/**
 * 獲取獨享鎖
 * tryAcquire 需要子類重寫方法
 */
public final void acquire(int arg) {
        // 嘗試獲取鎖,獲取成功返回 true,否則返回 false
    if (!tryAcquire(arg) &&  
        // 沒有獲取則加入隊列尾部,並通過 LockSupport.park(this)掛起自己
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) 
        // 進行自我中斷
        selfInterrupt(); 
}
// 線程自我中斷
static void selfInterrupt() {
    Thread.currentThread().interrupt();
}
/**
 * 試着釋放當前線程持有的獨佔鎖並喚醒後繼節點
 */
public final boolean release(int arg) {
    // tryRelease 獨享式釋放同步狀態,需要子類重寫
    if (tryRelease(arg)) { 
        Node h = head;
        if (h != null && h.waitStatus != 0)
            unparkSuccessor(h);
        return true;
    }
    return false;
}
/**
 * 獲取獨佔鎖的可中斷模式
 */
public final void acquireInterruptibly(int arg)
            throws InterruptedException {
    if (Thread.interrupted())
        // 當前線程如果中斷,則拋出中斷異常
        throw new InterruptedException();
    if (!tryAcquire(arg)) // 嘗試獲取鎖
        // 獲取鎖失敗,則調用 doAcquireInterruptibly 獲取獨享鎖的可中斷模式
        doAcquireInterruptibly(arg);
}

6.2 共享方式

 

public final void acquireShared(int arg) {
    if (tryAcquireShared(arg) < 0)
        // 獲取共享鎖的不中斷模式
        doAcquireShared(arg);
}
public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException {
    if (Thread.interrupted())
        throw new InterruptedException();
    if (tryAcquireShared(arg) < 0)
        doAcquireSharedInterruptibly(arg);
}
public final boolean releaseShared(int arg) {
    if (tryReleaseShared(arg)) {
        doReleaseShared();
        return true;
    }
    return false;
}

 

 

 

 

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