ReentrantLock 跟 Synchronized 區別
面試回答:
相同點:
-
synchronized 和 ReentrantLock 都是用來保護資源線程安全的。
-
都可以保證可見性。
-
synchronized 和 ReentrantLock 都擁有可重入的特點。
從基本語義和概念上說
-
synchronized
: Java 內建的同步機制 提供互斥性和可見性。 當一個線程獲取鎖后、其他線程只能等待或阻
synchronized
依賴 JVM 實現、使用更簡單、由 JVM 負責鎖的獲取和釋放。
-
ReentrantLock
: Java 5 提供的鎖實現。 通過lock()
方法顯式獲取鎖,unlock()
方法顯式釋放鎖。
但需要手動釋放鎖、否則可能導致死鎖。一般會把unlock
操作放入finally
塊來解鎖、以防忘記解鎖。
從鎖的公平性來說:
-
ReentrantLock
允許創建公平鎖 與非公平鎖 -
synchronized
始終是非公平鎖。當鎖被釋放時、哪個等待線程能獲取鎖是不確定的、可能導致某些線程長時間等待(饑餓)。
從靈活性來說:也就是可中斷獲取鎖
-
synchronized
鎖不夠靈活:synchronized
一個線程獲取鎖之后、其他線程想要獲取鎖只能等待、只能進入阻塞狀態、直到持有鎖的線程釋放這個鎖、可能這個等待過程會持續很久。 -
相比之下、ReentrantLock可以使用
lockInterruptibly
方法、不想等了可以中斷退出、避免無限期等待-
也可以嘗試非阻塞獲取鎖 (超時獲取):提供了嘗試非阻塞獲取鎖的方法 (
tryLock
()),可以立即返回是否成功獲取鎖。這使得線程可以根據情況決定是否繼續等待
-
從實現條件變量 (Condition)來說
-
ReentrantLock
提供了Condition
接口,可以將wait()
、notify()
、notifyAll()
等操作轉化為對象行為。 -
Condition
允許線程在特定條件滿足時掛起、并在條件滿足時被喚醒。 -
ReentrantLock
典型的應用場景是阻塞隊列 (如ArrayBlockingQueue
)、用于實現生產者-消費者模式。
從性能來說:(面試可以不回答 感覺沒必要)
-
早期版本的
synchronized
性能較差。 -
Java 6 之后,
synchronized
進行了大量優化 (如鎖膨脹、偏向鎖、輕量級鎖等)在低競爭情況下性能可能優于ReentrantLock
。 -
在高競爭情況下,
ReentrantLock
仍然可能具有一定優勢
選擇建議
-
synchronized: 優先考慮、尤其是在簡單同步場景下、代碼更簡潔、且由 JVM 管理鎖的釋放、更安全。
-
ReentrantLock: 當需要公平鎖、可中斷鎖、超時鎖,或者需要使用多個條件變量時、選擇 ReentrantLock。