【Java 并发编程】线程锁机制 ( 锁的四种状态 | 无锁状态 | 偏向锁 | 轻量级锁 | 重量级锁 | 锁竞争 | 锁升级 )
文章目錄
- 一、悲觀鎖示例 ( ReentrantLock )
- 二、重量級鎖弊端
- 三、鎖的四種狀態(tài) ( 無鎖狀態(tài) | 偏向鎖 | 輕量級鎖 | 重量級鎖 )
- 四、鎖的四種狀態(tài)之間的轉(zhuǎn)換 ( 無鎖狀態(tài) -> 偏向鎖 -> 輕量級鎖 -> 重量級鎖 )
一、悲觀鎖示例 ( ReentrantLock )
ReentrantLock 與 synchronized 都是悲觀鎖 ;
ReentrantLock 是 Lock 接口的實現(xiàn)類 ,
public class ReentrantLock implements Lock, java.io.Serializable { }Lock 是一種鎖的機制 , 調(diào)用 lock() 方法 , 表示要對下方的代碼進行加鎖 , 這些代碼是線程安全的 ;
代碼執(zhí)行完畢后 , 調(diào)用 unlock() 釋放鎖 ;
在 lock() 與 unlock() 之間的內(nèi)容 , 就是同步代碼塊內(nèi)容 ;
public interface Lock {void lock();void lockInterruptibly() throws InterruptedException;boolean tryLock();boolean tryLock(long time, TimeUnit unit) throws InterruptedException;void unlock();Condition newCondition(); }悲觀鎖都是重量級鎖 ;
二、重量級鎖弊端
JDK 1.21.21.2 之間 , 只有一個 synchronized 重量級鎖 ;
Java 虛擬機創(chuàng)建了線程 A , B 兩個線程 , JVM 將線程托管給操作系統(tǒng)進行調(diào)度執(zhí)行 , 線程同步依靠 synchronized 重量級鎖實現(xiàn) , 線程 A , B 之間會進行競爭 , 哪個搶到 synchronized 鎖 , 哪個線程就可以執(zhí)行 ;
使用 synchronized 使用起來效率很低 , 假如在 synchronized 同步代碼塊中 , 只有一行代碼 , 執(zhí)行 111 ms , 但是系統(tǒng)調(diào)度線程 , 可能需要 202020 ms 才能輪到線程執(zhí)行 , 線程執(zhí)行的時間遠遠小于調(diào)度時間 , 這樣線程執(zhí)行效率很低 ;
為了 Java 程序的提升執(zhí)行效率 , Java 引入了 444 種鎖狀態(tài) , 無鎖 , 偏向鎖 , 輕量級鎖 , 重量級鎖 ;
三、鎖的四種狀態(tài) ( 無鎖狀態(tài) | 偏向鎖 | 輕量級鎖 | 重量級鎖 )
Java 虛擬機堆內(nèi)存中的對象數(shù)據(jù)中 , 每個對象都有一個對象頭 , 結(jié)構(gòu)如下 :
對象頭 中封裝了 鎖的狀態(tài) , 當鎖的狀態(tài)發(fā)生改變時 , 對應(yīng)的鎖的標志位也進行相應(yīng)修改 ;
無鎖狀態(tài) : 不進行加鎖 , 線程不安全 ;
偏向鎖 : 第 111 個訪問 共享資源 的線程 A , 做一個標記 , 不加鎖 , 這個標記稱為 " 偏向鎖 " ; 偏向鎖 偏向第一個訪問的線程 ; 如果沒有新的線程競爭該鎖 , 則該 偏向鎖一直被該線程持有 , 不會釋放鎖 ; 如果出現(xiàn)多個線程同時訪問 , 持有偏向鎖的線程會 釋放該偏向鎖 , 并添加輕量級鎖 ;
- 鎖競爭 : 多個線程嘗試獲取同一個鎖 ;
- 沒有競爭 : 如果每次獲取都很順利 , 沒有出現(xiàn)阻塞 , 則沒有競爭 ;
- 有競爭 : 如果線程嘗試獲取鎖 , 但是鎖被其它線程持有 , 那么 該線程需要等待 , 期間 阻塞或自旋 , 只要是等待就會產(chǎn)生消耗 , 這就產(chǎn)生了鎖競爭 , 并且 有一定的性能消耗 ;
- 鎖競爭消耗 : 多數(shù)情況下鎖會被多個線程獲取多次 , 多個線程競爭一個鎖 , 這樣就存在競爭 , 競爭期間 阻塞或自旋 , 鎖獲取的代價很大 ;
- 偏向鎖優(yōu)點 : 降低了線程獲取鎖的代價 , 偏向鎖不存在鎖競爭問題 ;
- 偏向鎖意義 : 偏向鎖并 不是真正意義上的鎖 , 只是給單線程執(zhí)行加了層保險 , 如果沒有線程競爭該鎖 , 則正常執(zhí)行 , 如果有線程競爭 , 則將偏向鎖升級為輕量級鎖 ;
輕量級鎖 : 自旋鎖 , 等待期間一直做自旋操作 , 效率較高 , 但是空耗 CPU 性能 ; 自旋就是 while / for 循環(huán) ;
重量級鎖 : 系統(tǒng)提供的 synchronized , ReentrantLock 等重量級鎖 , 由操作系統(tǒng)進行調(diào)度 , 可進行阻塞 ;
四、鎖的四種狀態(tài)之間的轉(zhuǎn)換 ( 無鎖狀態(tài) -> 偏向鎖 -> 輕量級鎖 -> 重量級鎖 )
鎖的四種狀態(tài)之間轉(zhuǎn)換 : 在保證線程安全的前提下 , 盡可能提升效率 ;
-
無鎖 : 剛開始執(zhí)行時 , 無鎖 ;
-
無鎖 -> 偏向鎖 : 第 111 個線程訪問共享資源時 , 無鎖狀態(tài)升級為偏向鎖 ;
-
偏向鎖 -> 輕量級鎖 : 第 222 個線程再來訪問 共享資源 時 , 偏向鎖 升級為 輕量級鎖 ;
-
輕量級鎖 -> 重量級鎖 : 如果 自旋線程數(shù) 超過 CPU 核數(shù)一半 , 或 單個線程超過 101010 次自旋 , 自動將鎖升級為重量級鎖 ;
總結(jié)
以上是生活随笔為你收集整理的【Java 并发编程】线程锁机制 ( 锁的四种状态 | 无锁状态 | 偏向锁 | 轻量级锁 | 重量级锁 | 锁竞争 | 锁升级 )的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Java 并发编程】线程锁机制 ( 悲
- 下一篇: 【Java 并发编程】线程池机制 ( 测