📒 ReentrantLock 用法與源碼剖析筆記
🚀 一、ReentrantLock 核心特性
- 🔄 可重入性:同一線程可重復獲取鎖(最大遞歸次數為
Integer.MAX_VALUE
) - 🔧 公平性:支持公平鎖(按等待順序獲取)和非公平鎖(默認,允許插隊)
- ? 超時機制:
tryLock(long timeout, TimeUnit unit)
- 🚫 可中斷:
lockInterruptibly()
允許響應中斷 - 🔗 條件變量:
Condition
實現精準線程喚醒(對比Object.wait/notify
)
🛠? 二、基礎用法模板
ReentrantLock lock = new ReentrantLock();
// 非公平鎖(默認) vs 公平鎖(new ReentrantLock(true))lock.lock(); // 📌 阻塞獲取鎖
try {// 臨界區代碼
} finally {lock.unlock(); // ?? 必須放在 finally 塊!
}// 高級用法示例
if (lock.tryLock(1, TimeUnit.SECONDS)) { // ? 帶超時嘗試try {// ...} finally {lock.unlock();}
}
🔍 三、源碼架構分析
-
Sync 同步器(繼承 AQS)
- NonfairSync(非公平鎖實現)
- FairSync(公平鎖實現)
-
AQS 核心機制
- state 字段:鎖狀態計數器(0=未鎖定,>0=鎖定次數)
- CLH 隊列:線程等待隊列(雙向鏈表實現)
?? 四、關鍵方法源碼解析
🔑 1. lock() 方法對比
// 非公平鎖實現
final void lock() {if (compareAndSetState(0, 1)) // 🚀 直接嘗試插隊setExclusiveOwnerThread(Thread.currentThread());elseacquire(1);
}// 公平鎖實現
final void lock() {acquire(1); // ?? 必須排隊
}// AQS 核心方法
public final void acquire(int arg) {if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg))selfInterrupt();
}
🔄 2. tryAcquire 差異
// 非公平鎖 tryAcquire
protected final boolean tryAcquire(int acquires) {return nonfairTryAcquire(acquires); // 🎲 允許插隊
}// 公平鎖 tryAcquire
protected final boolean tryAcquire(int acquires) {if (getQueueLength() > 0 && getExclusiveOwnerThread() != Thread.currentThread()) {return false; // 🚧 隊列有等待線程時禁止獲取}// ...后續與非公平鎖相同
}
💡 五、設計亮點與注意事項
- � 性能取舍:非公平鎖吞吐量更高(減少線程切換),但可能產生線程饑餓
- � 鎖釋放必須:unlock() 必須執行(建議用 try-finally 包裹)
- 🧵 Condition 高級用法:實現多條件等待(典型應用:生產者-消費者模型)
- ?? 避免死鎖:加鎖順序要一致,超時機制可作為兜底
📊 六、與 synchronized 對比
特性 | ReentrantLock | synchronized |
---|---|---|
實現機制 | API 層面 | JVM 內置 |
鎖釋放 | 必須顯式 unlock() | 自動釋放 |
公平性 | 可配置 | 非公平 |
中斷響應 | 支持 | 不支持 |
條件變量 | 多 Condition | 單 Object monitor |
性能 | 高競爭時更優 | 優化后差距縮小 |
🌟 七、最佳實踐建議
- 🆚 優先選擇:需要高級功能時用 ReentrantLock,簡單場景用 synchronized
- 🧪 鎖測試:用 ThreadMXBean 檢測死鎖
- 📏 鎖粒度:盡量縮小鎖作用域
- 🧮 性能監控:關注
getQueueLength()
等統計方法