Semaphore原始碼解析

寒武沒有紀發表於2018-10-10

Semaphore 用來控制同時訪問特定資源的執行緒數量,使用 AQS 狀態值 state 代表許可數 permits

構造方法引數:

  • permits:許可數
  • fair:是否公平訊號量
public Semaphore(int permits) {
    sync = new NonfairSync(permits);
}

public Semaphore(int permits, boolean fair) {
    sync = fair ? new FairSync(permits) : new NonfairSync(permits);
}

首先來分析 acquire 獲取鎖方法

// Semaphore
public void acquire() throws InterruptedException {
    sync.acquireSharedInterruptibly(1);
}

以共享可中斷方式獲取鎖

// AbstractQueuedSynchronizer
public final void acquireSharedInterruptibly(int arg)
        throws InterruptedException {
    if (Thread.interrupted())
        throw new InterruptedException();
    if (tryAcquireShared(arg) < 0)
        doAcquireSharedInterruptibly(arg);
}

非公平方式獲取共享鎖

// Semaphore.NonfairSync
protected int tryAcquireShared(int acquires) {
    return nonfairTryAcquireShared(acquires);
}
// Semaphore.Sync
final int nonfairTryAcquireShared(int acquires) {
    // 迴圈
    for (;;) {
        int available = getState(); // 獲取當前狀態值(許可數)
        int remaining = available - acquires; // 剩餘可用許可數減去需要許可數
        // 如果剩餘可用許可數小於0 或 CAS設定當前剩餘可用許可數成功,則返回剩餘可用許可數
        if (remaining < 0 ||
            compareAndSetState(available, remaining))
            return remaining;
    }
}

公平方式獲取共享鎖,新增 hasQueuedPredecessors 方法判斷是否有先與當前執行緒獲取鎖的執行緒

// Semaphore.FairSync
protected int tryAcquireShared(int acquires) {
    for (;;) {
        // 新增判斷是否有先與當前執行緒獲取鎖的執行緒
        if (hasQueuedPredecessors())
            return -1;
        int available = getState();
        int remaining = available - acquires;
        if (remaining < 0 ||
            compareAndSetState(available, remaining))
            return remaining;
    }
}

分析 release 釋放鎖方法

// Semaphore
public void release() {
    sync.releaseShared(1);
}
// AbstractQueuedSynchronizer
public final boolean releaseShared(int arg) {
    if (tryReleaseShared(arg)) {
        doReleaseShared();
        return true;
    }
    return false;
}
// Semaphore.Sync
protected final boolean tryReleaseShared(int releases) {
    for (;;) {
        int current = getState(); // 獲取當前狀態值(許可數)
        int next = current + releases; // 當前剩餘可用許可數加上本地釋放許可數
        if (next < current) // overflow
            throw new Error("Maximum permit count exceeded");
        if (compareAndSetState(current, next)) // CAS設定狀態值(許可數)
            return true;
    }
}

相關文章