導航:首頁 > 編程語言 > 自旋鎖java

自旋鎖java

發布時間:2022-08-09 05:31:21

Ⅰ 說說java鎖有哪些種類,以及區別

鎖作為並發共享數據,保證一致性的工具,在JAVA平台有多種實現(如 synchronized 和 ReentrantLock等等 ) 。這些已經寫好提供的鎖為我們開發提供了便利,但是鎖的具體性質以及類型卻很少被提及。本系列文章將分析JAVA下常見的鎖名稱以及特性,為大家答疑解惑。
1、自旋鎖
自旋鎖是採用讓當前線程不停地的在循環體內執行實現的,當循環的條件被其他線程改變時 才能進入臨界區。如下

01 public class SpinLock {
02
03 private AtomicReference<Thread> sign =newAtomicReference<>();
04
05 public void lock(){
06 Thread current = Thread.currentThread();
07 while(!sign .compareAndSet(null, current)){
08 }
09 }
10
11 public void unlock (){
12 Thread current = Thread.currentThread();
13 sign .compareAndSet(current, null);
14 }
15 }
使用了CAS原子操作,lock函數將owner設置為當前線程,並且預測原來的值為空。unlock函數將owner設置為null,並且預測值為當前線程。
當有第二個線程調用lock操作時由於owner值不為空,導致循環一直被執行,直至第一個線程調用unlock函數將owner設置為null,第二個線程才能進入臨界區。
由於自旋鎖只是將當前線程不停地執行循環體,不進行線程狀態的改變,所以響應速度更快。但當線程數不停增加時,性能下降明顯,因為每個線程都需要執行,佔用CPU時間。如果線程競爭不激烈,並且保持鎖的時間段。適合使用自旋鎖。
註:該例子為非公平鎖,獲得鎖的先後順序,不會按照進入lock的先後順序進行。
Java鎖的種類以及辨析(二):自旋鎖的其他種類

鎖作為並發共享數據,保證一致性的工具,在JAVA平台有多種實現(如 synchronized 和 ReentrantLock等等 ) 。這些已經寫好提供的鎖為我們開發提供了便利,但是鎖的具體性質以及類型卻很少被提及。本系列文章將分析JAVA下常見的鎖名稱以及特性,為大家答疑解惑。

2.自旋鎖的其他種類
上篇我們講到了自旋鎖,在自旋鎖中 另有三種常見的鎖形式:TicketLock ,CLHlock 和MCSlock
Ticket鎖主要解決的是訪問順序的問題,主要的問題是在多核cpu上
01 package com.alipay.titan.dcc.dal.entity;
02
03 import java.util.concurrent.atomic.AtomicInteger;
04
05 public class TicketLock {
06 private AtomicInteger serviceNum = new AtomicInteger();
07 private AtomicInteger ticketNum = new AtomicInteger();
08 private static final ThreadLocal<Integer> LOCAL = new ThreadLocal<Integer>();
09
10 public void lock() {
11 int myticket = ticketNum.getAndIncrement();
12 LOCAL.set(myticket);
13 while (myticket != serviceNum.get()) {
14 }
15
16 }
17
18 public void unlock() {
19 int myticket = LOCAL.get();
20 serviceNum.compareAndSet(myticket, myticket + 1);
21 }
22 }
每次都要查詢一個serviceNum 服務號,影響性能(必須要到主內存讀取,並阻止其他cpu修改)。
CLHLock 和MCSLock 則是兩種類型相似的公平鎖,採用鏈表的形式進行排序,
01 importjava.util.concurrent.atomic.AtomicReferenceFieldUpdater;
02
03 public class CLHLock {
04 public static class CLHNode {
05 private volatile boolean isLocked = true;
06 }
07
08 @SuppressWarnings("unused")
09 private volatileCLHNode tail;
10 private static finalThreadLocal<CLHNode> LOCAL = new ThreadLocal<CLHNode>();
11 private static <CLHLock, CLHNode> UPDATER = AtomicReferenceFieldUpdater.newUpdater(CLHLock.class,
12 CLHNode.class,"tail");
13
14 public void lock() {
15 CLHNode node = new CLHNode();
16 LOCAL.set(node);
17 CLHNode preNode = UPDATER.getAndSet(this, node);
18 if (preNode != null) {
19 while (preNode.isLocked) {
20 }
21 preNode = null;
22 LOCAL.set(node);
23 }
24 }
25
26 public void unlock() {
27 CLHNode node = LOCAL.get();
28 if (!UPDATER.compareAndSet(this, node,null)) {
29 node.isLocked = false;
30 }
31 node = null;
32 }
33 }

CLHlock是不停的查詢前驅變數, 導致不適合在NUMA 架構下使用(在這種結構下,每個線程分布在不同的物理內存區域)
MCSLock則是對本地變數的節點進行循環。不存在CLHlock 的問題。
01 importjava.util.concurrent.atomic.AtomicReferenceFieldUpdater;
02
03 public class MCSLock {
04 public static class MCSNode {
05 volatile MCSNode next;
06 volatile boolean isLocked = true;
07 }
08
09 private static finalThreadLocal<MCSNode> NODE = new ThreadLocal<MCSNode>();
10 @SuppressWarnings("unused")
11 private volatileMCSNode queue;
12 private static <MCSLock, MCSNode> UPDATER = AtomicReferenceFieldUpdater.newUpdater(MCSLock.class,
13 MCSNode.class,"queue");
14
15 public void lock() {
16 MCSNode currentNode = new MCSNode();
17 NODE.set(currentNode);
18 MCSNode preNode = UPDATER.getAndSet(this, currentNode);
19 if (preNode != null) {
20 preNode.next = currentNode;
21 while (currentNode.isLocked) {
22
23 }
24 }
25 }
26
27 public void unlock() {
28 MCSNode currentNode = NODE.get();
29 if (currentNode.next == null) {
30 if (UPDATER.compareAndSet(this, currentNode, null)) {
31
32 } else {
33 while (currentNode.next == null) {
34 }
35 }
36 } else {
37 currentNode.next.isLocked = false;
38 currentNode.next = null;
39 }
40 }
41 }

Ⅱ 自旋鎖和互斥鎖的區別 java中lock Syntronized區別

自旋鎖(Spin
lock)
自旋鎖與互斥鎖有點類似,只是自旋鎖不會引起調用者睡眠,如果自旋鎖已經被別的執行單元保持,調用者就一直循環在那裡看是
否該自旋鎖的保持者已經釋放了鎖,"自旋"一詞就是因此而得名。其作用是為了解決某項資源的互斥使用。因為自旋鎖不會引起調用者睡眠,所以自旋鎖的效率遠
高於互斥鎖。雖然它的效率比互斥鎖高,但是它也有些不足之處:
1、自旋鎖一直佔用CPU,他在未獲得鎖的情況下,一直運行--自旋,所以佔用著CPU,如果不能在很短的時
間內獲得鎖,這無疑會使CPU效率降低。
2、在用自旋鎖時有可能造成死鎖,當遞歸調用時有可能造成死鎖,調用有些其他函數也可能造成死鎖,如
_to_user()、_from_user()、kmalloc()等。
因此我們要慎重使用自旋鎖,自旋鎖只有在內核可搶占式或SMP的情況下才真正需要,在單CPU且不可搶占式的內核下,自旋鎖的操作為空操作。自旋鎖適用於鎖使用者保持鎖時間比較短的情況下。
兩種鎖的加鎖原理
互斥鎖:線程會從sleep(加鎖)——>running(解鎖),過程中有上下文的切換,cpu的搶占,信號的發送等開銷。
自旋鎖:線程一直是running(加鎖——>解鎖),死循環檢測鎖的標志位,機制不復雜。
互斥鎖屬於sleep-waiting類型的鎖。例如在一個雙核的機器上有兩個線程(線程A和線程B),它們分別運行在Core0和
Core1上。假設線程A想要通過pthread_mutex_lock操作去得到一個臨界區的鎖,而此時這個鎖正被線程B所持有,那麼線程A就會被阻塞

Ⅲ Java鎖有哪些種類,以及區別

一、公平鎖/非公平鎖

公平鎖是指多個線程按照申請鎖的順序來獲取鎖。

非公平鎖是指多個線程獲取鎖的順序並不是按照申請鎖的順序,有可能後申請的線程比先申請的線程優先獲取鎖。有可能,會造成優先順序反轉或者飢餓現象。

對於Java ReentrantLock而言,通過構造函數指定該鎖是否是公平鎖,默認是非公平鎖。非公平鎖的優點在於吞吐量比公平鎖大。

對於Synchronized而言,也是一種非公平鎖。由於其並不像ReentrantLock是通過AQS的來實現線程調度,所以並沒有任何辦法使其變成公平鎖。

二、可重入鎖

可重入鎖又名遞歸鎖,是指在同一個線程在外層方法獲取鎖的時候,在進入內層方法會自動獲取鎖。說的有點抽象,下面會有一個代碼的示例。

對於Java ReentrantLock而言, 他的名字就可以看出是一個可重入鎖,其名字是Re entrant Lock重新進入鎖。

對於Synchronized而言,也是一個可重入鎖。可重入鎖的一個好處是可一定程度避免死鎖。

synchronized void setA() throws Exception{

Thread.sleep(1000);

setB();

}

synchronized void setB() throws Exception{

Thread.sleep(1000);

}

上面的代碼就是一個可重入鎖的一個特點,如果不是可重入鎖的話,setB可能不會被當前線程執行,可能造成死鎖。

三、獨享鎖/共享鎖

獨享鎖是指該鎖一次只能被一個線程所持有。

共享鎖是指該鎖可被多個線程所持有。

對於Java
ReentrantLock而言,其是獨享鎖。但是對於Lock的另一個實現類ReadWriteLock,其讀鎖是共享鎖,其寫鎖是獨享鎖。

讀鎖的共享鎖可保證並發讀是非常高效的,讀寫,寫讀 ,寫寫的過程是互斥的。

獨享鎖與共享鎖也是通過AQS來實現的,通過實現不同的方法,來實現獨享或者共享。

對於Synchronized而言,當然是獨享鎖。

四、互斥鎖/讀寫鎖

上面講的獨享鎖/共享鎖就是一種廣義的說法,互斥鎖/讀寫鎖就是具體的實現。

互斥鎖在Java中的具體實現就是ReentrantLock

讀寫鎖在Java中的具體實現就是ReadWriteLock

五、樂觀鎖/悲觀鎖

樂觀鎖與悲觀鎖不是指具體的什麼類型的鎖,而是指看待並發同步的角度。

悲觀鎖認為對於同一個數據的並發操作,一定是會發生修改的,哪怕沒有修改,也會認為修改。因此對於同一個數據的並發操作,悲觀鎖採取加鎖的形式。悲觀的認為,不加鎖的並發操作一定會出問題。

樂觀鎖則認為對於同一個數據的並發操作,是不會發生修改的。在更新數據的時候,會採用嘗試更新,不斷重新的方式更新數據。樂觀的認為,不加鎖的並發操作是沒有事情的。

從上面的描述我們可以看出,悲觀鎖適合寫操作非常多的場景,樂觀鎖適合讀操作非常多的場景,不加鎖會帶來大量的性能提升。

悲觀鎖在Java中的使用,就是利用各種鎖。

樂觀鎖在Java中的使用,是無鎖編程,常常採用的是CAS演算法,典型的例子就是原子類,通過CAS自旋實現原子操作的更新。

六、分段鎖

分段鎖其實是一種鎖的設計,並不是具體的一種鎖,對於ConcurrentHashMap而言,其並發的實現就是通過分段鎖的形式來實現高效的並發操作。

我們以ConcurrentHashMap來說一下分段鎖的含義以及設計思想,ConcurrentHashMap中的分段鎖稱為Segment,它即類似於HashMap(JDK7與JDK8中HashMap的實現)的結構,即內部擁有一個Entry數組,數組中的每個元素又是一個鏈表;同時又是一個ReentrantLock(Segment繼承了ReentrantLock)。

當需要put元素的時候,並不是對整個hashmap進行加鎖,而是先通過hashcode來知道他要放在那一個分段中,然後對這個分段進行加鎖,所以當多線程put的時候,只要不是放在一個分段中,就實現了真正的並行的插入。

但是,在統計size的時候,可就是獲取hashmap全局信息的時候,就需要獲取所有的分段鎖才能統計。

分段鎖的設計目的是細化鎖的粒度,當操作不需要更新整個數組的時候,就僅僅針對數組中的一項進行加鎖操作。

七、偏向鎖/輕量級鎖/重量級鎖

這三種鎖是指鎖的狀態,並且是針對Synchronized。在Java
5通過引入鎖升級的機制來實現高效Synchronized。這三種鎖的狀態是通過對象監視器在對象頭中的欄位來表明的。

偏向鎖是指一段同步代碼一直被一個線程所訪問,那麼該線程會自動獲取鎖。降低獲取鎖的代價。

輕量級鎖是指當鎖是偏向鎖的時候,被另一個線程所訪問,偏向鎖就會升級為輕量級鎖,其他線程會通過自旋的形式嘗試獲取鎖,不會阻塞,提高性能。

重量級鎖是指當鎖為輕量級鎖的時候,另一個線程雖然是自旋,但自旋不會一直持續下去,當自旋一定次數的時候,還沒有獲取到鎖,就會進入阻塞,該鎖膨脹為重量級鎖。重量級鎖會讓其他申請的線程進入阻塞,性能降低。

八、自旋鎖

在Java中,自旋鎖是指嘗試獲取鎖的線程不會立即阻塞,而是採用循環的方式去嘗試獲取鎖,這樣的好處是減少線程上下文切換的消耗,缺點是循環會消耗CPU。

典型的自旋鎖實現的例子,可以參考自旋鎖的實現

Ⅳ java 線程池機制的原理是什麼

線程池屬於對象池.所有對象池都具有一個非常重要的共性,就是為了最大程度復用對象.那麼線程池的最
重要的特徵也就是最大程度利用線程.
首先,創建線程本身需要額外(相對於執行任務而必須的資源)的開銷.
作業系統在每創建一個線程時,至少需要創建以下資源:
(1) 線程內核對象:用於對線程上下文的管理.
(2) 用戶模式執行棧.
(3) 內核模式執行棧.
這些資源被線程佔有後作業系統和用戶都無法使用.
相反的過程,銷毀線程需要回收資源,也需要一定開銷.
其次,過多的線程將導致過度的切換.線程切換帶來的性能更是不可估量.系統完成線程切換要經過以下過程:
(1) 從用戶模式切換到內核模式.
(2) 將CPU寄存器的值保存到當前線程的內核對象中.
(3)打開一個自旋鎖,根據調度策略決定下一個要執行的線程.釋放自旋鎖,如果要執行的線程不是同一進
程中的線程,還需要切換虛擬內存等進程環境.
(4) 將要執行的線程的內核對象的值寫到CPU寄存器中.
(5) 切換到用戶模式執行新線程的執行邏輯.
所以線程池的目的就是為了減少創建和切換線程的額外開銷,利用已經的線程多次循環執行多個任務從而提
高系統的處理能力.

Ⅳ 什麼時候用 Java 自旋鎖

所謂自旋鎖即死循環去嘗試獲得鎖,直到成功為止。
它的最大的好處,可以避免線程上下文切換。(須知Java線程上下文切換,需要操作系統由用戶態到內核態的切換,性能慢是可想而知的)
但是自旋鎖也有個不好之處在於,無線死循環消耗CPU, 因而如果等待時間很短就可以獲得鎖,那麼就可以提升程序整體性能。但是如果長時間得不到鎖,那得不償失。還是用wait,讓線程上下文切換來工作吧。

Ⅵ Java中有哪些鎖,區別是什麼

【1】公平所和非公平所。
公平鎖:是指按照申請鎖的順序來獲取鎖,
非公平所:線程獲取鎖的順序不一定按照申請鎖的順序來的。

//默認是不公平鎖,傳入true為公平鎖,否則為非公平鎖
ReentrantLock reentrantLock = new ReetrantLock();
1
2
【2】共享鎖和獨享鎖
獨享鎖:一次只能被一個線程所訪問
共享鎖:線程可以被多個線程所持有。
ReadWriteLock 讀鎖是共享鎖,寫鎖是獨享鎖。
【3】樂觀鎖和悲觀鎖。
樂觀鎖:對於一個數據的操作並發,是不會發生修改的。在更新數據的時候,會嘗試採用更新,不斷重入的方式,更新數據。
悲觀鎖:對於同一個數據的並發操作,是一定會發生修改的。因此對於同一個數據的並發操作,悲觀鎖採用加鎖的形式。悲觀鎖認為,不加鎖的操作一定會出問題,
【4】分段鎖
1.7及之前的concurrenthashmap。並發操作就是分段鎖,其思想就是讓鎖的粒度變小。
【5】偏向鎖是指一段同步代碼一直被一個線程所訪問,那麼該線程會自動獲取鎖。降低獲取鎖的代價
輕量級鎖
重量級鎖
【6】自旋鎖
自旋鎖

Ⅶ java中的同步代碼塊,為什麼隨便放個對象,就可以鎖住代碼塊呢什麼原理

synchronized(這里的對象你看成一道門) {
這里是一個人進來了,把門反鎖了

需要同步操作的代碼

這里是裡面的人事情做完了,出去了,門開著其他人可以進了
}

至於怎麼鎖的,這是java和jvm的規定和實現細節,作為普通程序員沒必要深入那麼多。

Ⅷ java線程鎖有幾種

1、自旋鎖
2、自旋鎖的其他種類
3、阻塞鎖
4、可重入鎖
5、讀寫鎖
6、互斥鎖
7、悲觀鎖
8、樂觀鎖
9、公平鎖
10、非公平鎖
11、偏向鎖
12、對象鎖
13、線程鎖
14、鎖粗化
15、輕量級鎖
16、鎖消除
17、鎖膨脹
18、信號量

Ⅸ Java自旋與睡眠的效率

進程A獲得自旋鎖後,進行可能引起休眠的操作後(例如_from_user等),進程將會被切換出去,這個時候另外一個進程B企圖獲取本自旋鎖,死鎖就會發生。

閱讀全文

與自旋鎖java相關的資料

熱點內容
程序員會壓抑 瀏覽:680
物探編程 瀏覽:300
vuepdf預覽 瀏覽:325
迷你世界出編程軟體了 瀏覽:673
res文件夾有哪些 瀏覽:142
交通信號燈單片機課程設計 瀏覽:826
如何測試流媒體伺服器的並發能力 瀏覽:161
溯源碼有分國家認證的嗎 瀏覽:218
如何通過app查詢產檢報告 瀏覽:944
拉結爾安卓手機怎麼用 瀏覽:695
驅動級進程代理源碼 瀏覽:782
androidshape畫線 瀏覽:511
程序員想辭職被拒絕 瀏覽:101
java面試邏輯 瀏覽:749
如何下載全英文app 瀏覽:724
js函數式編程指南 瀏覽:380
為什麼安卓手機相機啟動會卡 瀏覽:341
python中t是什麼意思 瀏覽:765
移動硬碟內存加密 瀏覽:407
單片機測角度 瀏覽:864