關於Java 鎖的知識整理與回顧(個人筆記): 鎖有哪些,分別用來幹嘛? Java實現鎖有兩種方式,synchronized關鍵字和Lock (1)Lock(可判斷鎖狀態) Lock是基於JDK層面實現。Lock的實現主要有ReentrantLock、ReadLock和WriteLock(引出鎖分類 ...
關於Java 鎖的知識整理與回顧(個人筆記):
鎖有哪些,分別用來幹嘛?
Java實現鎖有兩種方式,synchronized關鍵字和Lock
(1)Lock(可判斷鎖狀態)
Lock是基於JDK層面實現。Lock的實現主要有ReentrantLock、ReadLock和WriteLock(引出鎖分類:)
①樂觀鎖/悲觀鎖:
樂觀鎖認為讀多寫少,樂觀的認為拿數據時,不會改數據,所以不會上鎖,而在更新數據時才會判斷有無數據更新。悲觀鎖悲觀的認為,寫多,拿數據時先設定數據被修改了,每次在讀寫數據時都會上鎖。
②公平鎖/非公平鎖:
ReentrantLock在構造函數中提供是否公平鎖的初始化方式(預設是非公平鎖,就是說可以變成公平鎖。即他和synchronized不同之處之一):
public ReentrantLock() { sync = new NonfairSync(); }
public ReentrantLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync(); }
非公平鎖不按套路出牌,有可能造成“饑餓”現象,但是它的實際執行效率、吞吐量要高於公平鎖。
③獨享鎖/共用鎖
獨享鎖是指該鎖一次只能被一個線程所持有 (ReentrantLock、 Synchronized),共用鎖反之(ReadWriteLock)。
④互斥鎖/讀寫鎖(ReadWriteLock)
互斥鎖/讀寫鎖像是獨享鎖/共用鎖的具體的實現。(從字面意思就解釋很清楚了)
⑤可重入鎖
指同一個線程在外層方法獲取鎖的時候,在進入內層方法會自動獲取鎖(ReentrantLock和Synchronized)。可重入鎖可一定程度避免死鎖。
⑥自旋鎖
自旋鎖是指嘗試獲取鎖的線程不會阻塞,而是採用迴圈的方式嘗試獲取鎖。“採用迴圈的方式”說明要一直占用CPU資源,浪費啊。在判斷持有鎖的線程會在很短的時間釋放鎖,用它就划算了,不用上下文來回切換了。
⑦偏向鎖/輕量級鎖/重量級鎖
這是jdk1.6中對Synchronized鎖做的優化,對象頭在不同鎖狀態下的標誌位存儲。
偏向鎖:加鎖/解鎖開銷少,適用於只有一個線程訪問同步塊場景;輕量級鎖:競爭線程不會堵塞,追求響應速度時用它;重量級鎖:線程競爭不使用自旋,不會消耗CPU,吞吐量大。(儘量先考慮使用輕量級鎖)
(2)synchronized(不可判斷鎖狀態):
synchronized基於JVM層面實現。synchronized可以把任意的非Null的對象當作瑣,它是非公平鎖(且無法變成公平鎖)、獨享的可重入的悲觀鎖。使用synchronized比較省事兒,但是它是一個重量級操作,需要調用操作系統相關介面,性能較低,鎖開銷可能較大。
同時,synchronized它在不斷的被優化,在JDK1.5之後synchronized引入了偏向鎖,輕量級鎖和重量級鎖,java 6有適應自旋、鎖粗化、偏向鎖等,之後還設置一堆標記位,減少獲得鎖和釋放鎖帶來的性能消耗,鎖開銷小了,效率高了。