java.util.concurrent.locks.Lock 是 JDK 1.5 引入的顯式鎖機制,提供比 synchronized 更豐富的並發控制能力(可中斷、超時、公平鎖、條件變量)。本文對比兩者差異,詳解核心 API 並給出生產級使用模式。
| 維度 | synchronized | Lock |
|---|---|---|
| 本質 | JVM 內置關鍵字 | Java 類庫 API (interface) |
| 釋放方式 | 自動 (塊結束/異常) | 手動 unlock() (必須在 finally 中) |
| 可中斷 | 不可中斷 | lockInterruptibly() 支持中斷 |
| 超時獲取 | 不支持 | tryLock(timeout) 支持 |
| 公平鎖 | 非公平 (JVM 優化後) | ReentrantLock(true) 可選公平 |
| 條件變量 | wait/notify | newCondition() 多條件隊列 |
void lock(); // 獲取鎖,阻塞直到成功
void lockInterruptibly() throws InterruptedException; // 可中斷獲取鎖
boolean tryLock(); // 非阻塞嘗試獲取,立即返回
boolean tryLock(long time, TimeUnit unit); // 超時嘗試獲取
void unlock(); // 釋放鎖
Condition newCondition(); // 創建條件變量
private final ReentrantLock lock = new ReentrantLock();
public void safeOperation() {
lock.lock(); // 1. 獲取鎖
try {
// 2. 臨界區業務邏輯
System.out.println(Thread.currentThread().getName() + " 處理業務");
} catch (Exception e) {
// 3. 異常處理
} finally {
// 4. 必須釋放鎖,防止死鎖
lock.unlock();
}
}
鐵律:lock() 與 unlock() 必須配對,且 unlock() 放在 finally 中。
lock.lock();
lock.lock(); lock.lock(); // 同一線程可重複獲取
try { /* 業務 */ }
finally {
lock.unlock(); lock.unlock(); lock.unlock(); // 必須對應釋放相同次數
}
if (lock.tryLock(1, TimeUnit.SECONDS)) {
try { /* 業務 */ }
finally { if (lock.isHeldByCurrentThread()) lock.unlock(); }
} else {
// 超時處理:降級、重試、拋棄、告警
log.warn("獲取鎖超時,放棄本次操作");
}
適用於分布式鎖降級、高併發熱點資源保護等場景。
private final Condition notFull = lock.newCondition();
private final Condition notEmpty = lock.newCondition();
// 生產者
lock.lock();
try {
while (queue.size() == capacity) notFull.await();
queue.add(item);
notEmpty.signal();
} finally { lock.unlock(); }
// 消費者
lock.lock();
try {
while (queue.isEmpty()) notEmpty.await();
Item item = queue.poll();
notFull.signal();
return item;
} finally { lock.unlock(); }
相比 wait/notify,Condition 支持多條件隊列,實現「生產者只喚醒消費者、消費者只喚醒生產者」的精準控制。
synchronized (偏向鎖、輕量級鎖、自適應自旋性能優異)LockReentrantReadWriteLock