首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

ReentrantLock 源碼深度解析:基於 AQS 的公平/非公平鎖實現原理

     編輯:Java 綜合教學

ReentrantLock 源碼深度解析:基於 AQS 的公平/非公平鎖實現原理

整體架構

  • ReentrantLock 委派給內部類 Sync(繼承 AbstractQueuedSynchronizer)
  • Sync 兩個子類:NonfairSync(預設)、FairSync
  • 核心依賴 LockSupport、Unsafe 進行線程阻塞/喚醒與 CAS 操作

鎖獲取流程

1. nonfairTryAcquire(非公平嘗試)

final boolean nonfairTryAcquire(int acquires) {
    Thread current = Thread.currentThread();
    int c = getState();
    if (c == 0) {
        // 無鎖時 CAS 佔用
        if (compareAndSetState(0, acquires)) {
            setExclusiveOwnerThread(current);
            return true;
        }
    } else if (current == getExclusiveOwnerThread()) {
        // 重入:直接疊加 state
        int nextc = c + acquires;
        if (nextc < 0) throw new Error("Maximum lock count exceeded");
        setState(nextc);
        return true;
    }
    return false;
}

特點:非公平搶佔、重入無需 CAS、偏向當前持有線程。

2. 入隊列

  • CLH 隊列(雙向鏈表),節點封裝線程與模式(獨占/共享)
  • addWaiter 快速尾插(CAS),失敗進 enq 自旋入隊

3. acquireQueued(排隊獲取)

final boolean acquireQueued(final Node node, int arg) {
    boolean interrupted = false;
    for (;;) {
        Node p = node.predecessor();
        if (p == head && tryAcquire(arg)) {
            setHead(node); // 成功掛為頭節點
            p.next = null; // help GC
            return interrupted;
        }
        // 前驅非頭或獲取失敗 → 判斷是否應阻塞
        if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt())
            interrupted = true;
    }
}

4. shouldParkAfterFailedAcquire(阻塞判定)

  • 前驅狀態 SIGNAL → 可安全 park
  • 前驅狀態 CANCELLED → 跳過取消節點重鏈
  • 其他 → CAS 設前驅為 SIGNAL,下輪嘗試

5. parkAndCheckInterrupt

LockSupport.park(this); // 交給 OS 核心阻塞
return Thread.interrupted();

釋放鎖流程

1. tryRelease

protected final boolean tryRelease(int releases) {
    int c = getState() - releases;
    if (Thread.currentThread() != getExclusiveOwnerThread())
        throw new IllegalMonitorStateException();
    boolean free = false;
    if (c == 0) {
        free = true;
        setExclusiveOwnerThread(null);
    }
    setState(c);
    return free;
}

2. unparkSuccessor(喚醒後繼)

  • 頭節點狀態 < 0 → CAS 重置為 0
  • 尋找首個非取消後繼節點(從尾部反向掃描)
  • LockSupport.unpark(thread) 喚醒

非公平特性:新來線程可能在 nonfairTryAcquire 直接搶佔,排隊線程不一定優先獲得。

公平鎖差異

protected final boolean tryAcquire(int acquires) {
    Thread current = Thread.currentThread();
    int c = getState();
    if (c == 0) {
        // 公平:檢查隊列是否有前驅等待者
        if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) {
            setExclusiveOwnerThread(current);
            return true;
        }
    } else if (current == getExclusiveOwnerThread()) {
        // 重入邏輯相同
    }
    return false;
}

總結

  • AQS 狀態變量 state 表示鎖計數
  • CLH 隊列管理等待線程,狀態機控制阻塞/喚醒
  • 非公平鎖吞吐高,公平鎖避免飢餓
  • 條件變數 Condition 同樣基於 AQS 實現
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved