JDK java.util.concurrent(JUC)包是 Java 高併發編程的基石。本文系統講解 JUC 中核心同步器、併發容器的原理、用法與源碼實現,助你構建高效穩定的併發系統。
基本用法: 必須在 finally 中 unlock(),避免異常導致鎖永不釋放。
lock.lock();
try {
// 臨界區操作
} finally {
lock.unlock();
}
| 特性 | 說明 | 關鍵 API |
|---|---|---|
| 可重入 | 同一線程可重複獲取鎖,計數器+1,需對應釋放次數 | 內部實現 |
| 可中斷 | lockInterruptibly() 可響應中斷,解決死鎖利器 | lockInterruptibly() |
| 可限時 | tryLock(timeout) 超時自動放棄,避免無限等待 | tryLock(long, TimeUnit) |
| 公平鎖 | 構造器 new ReentrantLock(true) 保證 FIFO 獲取鎖,犧牲吞吐量換公平 | 構造器參數 |
// 死鎖場景:線程1鎖A→等B,線程2鎖B→等A
// 解決:使用 lockInterruptibly() + 死鎖檢測線程中斷死鎖線程
ThreadMXBean mbean = ManagementFactory.getThreadMXBean();
long[] deadlocked = mbean.findDeadlockedThreads();
if (deadlocked != null) {
for (long id : deadlocked) {
Thread.getAllStackTraces().keySet().stream()
.filter(t -> t.getId() == id)
.findFirst()
.ifPresent(Thread::interrupt); // 中斷死鎖線程
}
}
綁定 ReentrantLock,替代 Object.wait/notify,支持多條件隊列(如「不滿」「不空」)。
ReentrantLock lock = new ReentrantLock();
Condition notFull = lock.newCondition();
Condition notEmpty = lock.newCondition();
// 生產者
lock.lock();
try {
while (queue.size() == capacity) notFull.await();
queue.add(item);
notEmpty.signal();
} finally { lock.unlock(); }
允許 N 個線程同時進入臨界區,許可證耗盡則阻塞。許可證數=1 時退化為互斥鎖。
Semaphore semaphore = new Semaphore(5); // 允許 5 線程並發
semaphore.acquire(); // 獲取許可
try { /* 業務 */ } finally { semaphore.release(); }
核心語義: 讀讀共存、讀寫互斥、寫寫互斥。適用於「讀多寫少」場景。
ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
Lock readLock = rwLock.readLock();
Lock writeLock = rwLock.writeLock();
// 讀操作
readLock.lock();
try { return data; } finally { readLock.unlock(); }
// 寫操作
writeLock.lock();
try { data = newValue; } finally { writeLock.unlock(); }
主線程 await() 等待 N 個子線程 countDown() 歸零,**不可重用**。典型場景:火箭發射前多系統檢查。
N 線程 await() 歸零後觸發 barrierAction,**自動重置可重複使用**。典型場景:多階段任務同步(集合→出發→任務→集合)。
基於「許可證」模型:park() 消費許可,unpark(thread) 產生許可。**解決 suspend/resume 死鎖缺陷**,支持中斷響應(不拋異常,通過 Thread.interrupted() 判斷)。
三大支柱:
volatile int state 表示鎖狀態(0=釋放,1=持有,>1=重入次數)Node,線程入隊自旋等待LockSupport.park(this) 掛起,unpark() 喚醒// 獲取鎖核心邏輯
final void lock() {
if (compareAndSetState(0, 1)) // CAS 嘗試獲取
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1); // 進入隊列排隊
}
// 隊列入隊 + 自旋 + Park
private final boolean acquireQueued(Node node, int arg) {
while (true) {
Node p = node.predecessor();
if (p == head && tryAcquire(arg)) { // 嘗試獲取
setHead(node);
return false;
}
if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt())
return true; // 中斷返回
}
}
Segment[] 數組,每個 Segment 繼承 ReentrantLockput 先定位 Segment(高位 hash),再鎖定該 Segment 操作size() 需鎖定所有 Segment 求和,較重Node[] 數組 + 鏈表/紅黑樹putVal:CAS 嘗試插入頭節點 → 失敗則 synchronized(node) 鎖住鏈表頭節點transfer,**細粒度並發擴容**size() 使用 LongAdder 累加器,高併發下極快| 組件 | 核心適用場景 | 關鍵注意點 |
|---|---|---|
| ReentrantLock | 需要可中斷、超時、公平語義的互斥 | 必須 finally unlock;高併發考慮 LongAdder/StampedLock |
| Condition | 多條件協作(如雙端隊列不滿/不空) | 必須在 lock 保護下 await/signal |
| Semaphore | 限流、資源池控制(連接池、線程池) | 許可證數量設定;acquire 可中斷 |
| ReadWriteLock | 讀多寫少的共享數據結構 | 寫線程饑風險;考慮 StampedLock |
| CountDownLatch | 一次性多線程等待彙聚 | 不可重用;計數歸零後失效 |
| CyclicBarrier | 多階段迭代任務同步 | 可重用;barrierAction 異常會打破屏障 |
| ConcurrentHashMap | 高併發 Map 存取 | JDK8+ 首選;複合操作需額外加鎖 |
| BlockingQueue | 生產消費者解耦 | 有界防 OOM;選擇正確實現類 |