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

Java 8 AQS 深度解析:AbstractQueuedSynchronizer 獨占鎖實現原理與 ReentrantLock 源碼追蹤

     編輯:Java 相關知識

AbstractQueuedSynchronizer (AQS) 是 JUC 並發包核心基石,ReentrantLock、CountDownLatch、Semaphore 等均構建於其上。本文從 ReentrantLock 切入,深度剖析 AQS 獨占鎖實現。

AQS 核心設計

  • state:volatile int 狀態變數,獨占鎖表「持鎖次數」,共享鎖表「可用資源數」
  • CLH 隊列:Node 雙向鏈表,頭節點為佔用鎖線程,尾節點為最新入隊線程
  • 模板方法:tryAcquire/tryRelease 留給子類實現具體語義

ReentrantLock.lock() 流程

  1. NonfairSync.lock():先 compareAndSetState(0,1) 搶鎖,失敗進 acquire(1)
  2. AQS.acquire():tryAcquire() 失敗 → addWaiter(Node.EXCLUSIVE) 入隊 → acquireQueued() 自旋嘗試獲取
  3. acquireQueued():前驅為頭節點且 tryAcquire 成功 → setHead(node) 佔用鎖;否則檢查前驅 waitStatus == SIGNAL → LockSupport.park() 掛起
  4. 被喚醒後循環重試,直到獲取鎖或中斷

公平鎖 vs 非公平鎖

  • 公平鎖:FairSync.tryAcquire() 先檢查 hasQueuedPredecessors(),有排隊線程則不搶佔
  • 非公平鎖:NonfairSync.lock() 直接 CAS 搶鎖,成功即佔用,可能導致飢餓但吞吐更高

ReentrantLock.unlock() 流程

  1. Sync.tryRelease(1):state--,歸零時 setExclusiveOwnerThread(null)
  2. AQS.release():釋放成功 → unparkSuccessor(head) 喚醒後繼節點
  3. unparkSuccessor():從尾部向前尋找 waitStatus < 0 的節點 → LockSupport.unpark(thread)

Node 狀態機

CANCELLED(1)   // 取消等待
SIGNAL(-1)     // 後繼需喚醒
CONDITION(-2)  // 條件隊列
PROPAGATE(-3)  // 共享模式傳播

關鍵洞見

AQS 並未使用 synchronized 或特殊指令,純 Java 實現:volatile state + CAS + CLH 隊列 + LockSupport。子類只需實現 tryAcquire/tryRelease 定義語義,AQS 負責排隊、阻塞、喚醒、內存可見性。

延伸:共享鎖實現

CountDownLatch、Semaphore 使用 tryAcquireShared/tryReleaseShared,隊列節點 Node.SHARED,喚醒時傳播至所有共享節點。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved