面試高頻題、實戰選型依據。本文從 **實現層級、鎖粒度、獲取策略、條件變量** 四個維度,配合代碼片段,給出 synchronized 與 Lock 的本質區別與決策建議。
| 維度 | synchronized | Lock (ReentrantLock) |
|---|---|---|
| 實現層級 | JVM 內置(字節碼 monitorenter/monitorexit) | JDK API(AQS + CAS + Park/Unpark) |
| 死鎖風險 | 無法手動釋放,異常自動釋放 | 需 finally 中 unlock(),否則極易死鎖 |
| 鎖粒度 | 僅支持互斥鎖(獨佔) | 支持 ReadWriteLock:讀鎖共享、寫鎖獨佔、讀寫互斥 |
| 獲取策略 | 阻塞式,無超時、無中斷、無輪詢 | tryLock() 非阻塞、tryLock(timeout) 定時、lockInterruptibly() 可中斷 |
| 條件變量 | wait/notify/notifyAll 單一條件 | newCondition() 多條件隊列,精準喚醒 |
Lock lock = new ReentrantLock();
lock.lock();
try {
// 臨界區
} finally {
lock.unlock(); // 必須釋放,否則死鎖
}
ReadWriteLock rwl = new ReentrantReadWriteLock();
Lock r = rwl.readLock(); // 多線程可並發讀
Lock w = rwl.writeLock(); // 寫獨佔,讀寫互斥
r.lock(); try { /* 讀操作 */ } finally { r.unlock(); }
w.lock(); try { /* 寫操作 */ } finally { w.unlock(); }
if (lock.tryLock()) {
try { /* 獲取成功 */ } finally { lock.unlock(); }
} else {
/* 未獲取到,執行降級邏輯或重試 */
}
Lock lock = new ReentrantLock();
Condition notFull = lock.newCondition();
Condition notEmpty = lock.newCondition();
// 生產者
lock.lock(); try { while (full) notFull.await(); ... notEmpty.signal(); } finally { lock.unlock(); }
// 消費者
lock.lock(); try { while (empty) notEmpty.await(); ... notFull.signal(); } finally { lock.unlock(); }
synchronized(JVM 優化好、可讀性強、自動釋放);ReentrantReadWriteLock;ReentrantLock;Lock + Condition;synchronized 引入偏向鎖、輕量級鎖、鎖消除等優化,性能差距已極小,優先考慮代碼簡潔性。