關於Java鎖幾個解釋
分類
- 公平鎖/非公平鎖
- 可重入鎖
- 獨享鎖/共享鎖
- 互斥鎖/讀寫鎖
- 樂觀鎖/悲觀鎖
- 分段鎖
- 偏向鎖/輕量級鎖/重量級鎖
- 自旋鎖
公平鎖/非公平鎖
公平鎖:各個執行緒按請求鎖的順序來獲取物件鎖。
非公平鎖:公平鎖的反面,缺點,優先順序反轉,高優先順序的可能得不到鎖,飢餓現象。
優點:高併發的吞吐量比公平鎖大。對應的類是Synchronized,ReentrantLock,區別reentrantlock可以實現公平鎖,synchronized不行。
可重入鎖
又名遞迴鎖,是指在同一個執行緒在外層方法獲取鎖的時候,在進入內層方法會自動獲取鎖。
案例
一個帶synchronized方法A,裡面含有一個synchronized方法B,當開始執行方法A時候,現場執行緒會去獲取鎖,程式碼執行到方法B的時候,該執行緒還會去獲取B方法的鎖。優點,防止死鎖,打個比方,就上面的案例,假設執行B的時候沒有去獲取鎖,一個線做的過程是AB,另一個執行緒執行的是BA,這個時候AB的A鎖定了,BA的B鎖定了,AB執行B過不去,BA執行A過不去,資源互鎖,死鎖就產生了。
synchronized void A() throws Exception{ B(); } synchronized void B() throws Exception{ }
獨享鎖/共享鎖
這個東西就是一個概念,獨享鎖就是該鎖只能給一個執行緒用,共享鎖就是該鎖可以給多個執行緒用。
獨享鎖有Synchronized,ReentrantLock。readwritelock的寫鎖。
共享鎖有readwritelock的讀鎖。
互斥鎖/讀寫鎖
也是一種概念。
互斥鎖在Java中的具體實現就是ReentrantLock
讀寫鎖在Java中的具體實現就是ReadWriteLock
樂觀鎖/悲觀鎖
這也是一種概念。
樂觀鎖認為,多個執行緒對同一個資料就進行操作是沒有影響的,在更新資料的時候,會採用嘗試更新,不斷更新的方式更新資料。(換句話說它認為所有測操作都是讀操作)。
悲觀鎖認為,多個執行緒對同一個資料操作都是更新操作,不加鎖的併發操作一定會出問題,需要對那段程式碼加鎖。(換句話說它認為所有測操作都是寫操作)。
分段鎖
一種概念。
對於ConcurrentHashMap
而言,其併發的實現就是通過分段鎖的形式來實現高效的併發操作。
ConcurrentHashMap
中的分段鎖稱為Segment,它即類似於HashMap的結構,即內部擁有一個Entry陣列,陣列中的每個元素又是一個連結串列;同時又是一個ReentrantLock(Segment繼承了ReentrantLock)。
當需要put元素的時候,並不是對整個hashmap進行加鎖,而是先通過hashcode來知道他要放在那一個分段(桶)中,然後對這個分段(桶)進行加鎖,所以當多執行緒put的時候,只要不是放在一個分段中,就實現了真正的並行的插入。但是,在統計size的時候,可就是獲取hashmap全域性資訊的時候,就需要獲取所有的分段鎖才能統計。
分段鎖的設計目的是細化鎖的粒度,當操作不需要更新整個陣列的時候,就僅僅針對陣列中的一項進行加鎖操作。
偏向鎖/輕量級鎖/重量級鎖
這三種鎖是指鎖的狀態,並且是針對Synchronized
。
在Java 5通過引入鎖升級的機制來實現高效Synchronized
。這三種鎖的狀態是通過物件監視器在物件頭中的欄位來表明的。
偏向鎖: 指一段同步程式碼一直被一個執行緒所訪問,那麼該執行緒會自動獲取鎖。降低獲取鎖的代價。
輕量級鎖:指當鎖是偏向鎖的時候,被另一個執行緒所訪問,偏向鎖就會升級為輕量級鎖,其他執行緒會通過自旋的形式嘗試獲取鎖,不會阻塞,提高效能。
重量級鎖:指當鎖為輕量級鎖的時候,另一個執行緒雖然是自旋,但自旋不會一直持續下去,當自旋一定次數的時候,還沒有獲取到鎖,就會進入阻塞,該鎖膨脹為重量級鎖。重量級鎖會讓其他申請的執行緒進入阻塞,效能降低。
自旋鎖
在Java中,自旋鎖是指嘗試獲取鎖的執行緒不會立即阻塞,而是採用迴圈的方式去嘗試獲取鎖,這樣的好處是減少執行緒上下文切換的消耗,缺點是迴圈會消耗CPU。