色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

聊聊Java中那18把鎖

jf_ro2CN3Fa ? 來源:愛笑的架構師 ? 2023-05-15 09:44 ? 次閱讀

樂觀鎖和悲觀鎖

悲觀鎖

悲觀鎖對應于生活中悲觀的人,悲觀的人總是想著事情往壞的方向發展。

舉個生活中的例子,假設廁所只有一個坑位了,悲觀鎖上廁所會第一時間把門反鎖上,這樣其他人上廁所只能在門外等候,這種狀態就是「阻塞」了。

回到代碼世界中,一個共享數據加了悲觀鎖,那線程每次想操作這個數據前都會假設其他線程也可能會操作這個數據,所以每次操作前都會上鎖,這樣其他線程想操作這個數據拿不到鎖只能阻塞了。

8a552608-f28d-11ed-90ce-dac502259ad0.png

Java 語言中 synchronized 和 ReentrantLock等就是典型的悲觀鎖,還有一些使用了 synchronized 關鍵字的容器類如 HashTable 等也是悲觀鎖的應用。

樂觀鎖

樂觀鎖 對應于生活中樂觀的人,樂觀的人總是想著事情往好的方向發展。

舉個生活中的例子,假設廁所只有一個坑位了,樂觀鎖認為:這荒郊野外的,又沒有什么人,不會有人搶我坑位的,每次關門上鎖多浪費時間,還是不加鎖好了。你看樂觀鎖就是天生樂觀!

回到代碼世界中,樂觀鎖操作數據時不會上鎖,在更新的時候會判斷一下在此期間是否有其他線程去更新這個數據。

8a776b28-f28d-11ed-90ce-dac502259ad0.png

樂觀鎖可以使用版本號機制和CAS算法實現。在 Java 語言中 java.util.concurrent.atomic包下的原子類就是使用CAS 樂觀鎖實現的。

兩種鎖的使用場景

悲觀鎖和樂觀鎖沒有孰優孰劣,有其各自適應的場景。

樂觀鎖適用于寫比較少(沖突比較小)的場景,因為不用上鎖、釋放鎖,省去了鎖的開銷,從而提升了吞吐量。

如果是寫多讀少的場景,即沖突比較嚴重,線程間競爭激勵,使用樂觀鎖就是導致線程不斷進行重試,這樣可能還降低了性能,這種場景下使用悲觀鎖就比較合適。

獨占鎖和共享鎖

獨占鎖

獨占鎖是指鎖一次只能被一個線程所持有。如果一個線程對數據加上排他鎖后,那么其他線程不能再對該數據加任何類型的鎖。獲得獨占鎖的線程即能讀數據又能修改數據。

8a9dbd96-f28d-11ed-90ce-dac502259ad0.png

JDK中的synchronized和java.util.concurrent(JUC)包中Lock的實現類就是獨占鎖。

共享鎖

共享鎖是指鎖可被多個線程所持有。如果一個線程對數據加上共享鎖后,那么其他線程只能對數據再加共享鎖,不能加獨占鎖。獲得共享鎖的線程只能讀數據,不能修改數據。

8ab172d2-f28d-11ed-90ce-dac502259ad0.png

在 JDK 中 ReentrantReadWriteLock 就是一種共享鎖。

互斥鎖和讀寫鎖

互斥鎖

互斥鎖是獨占鎖的一種常規實現,是指某一資源同時只允許一個訪問者對其進行訪問,具有唯一性和排它性。

8acdf6b4-f28d-11ed-90ce-dac502259ad0.png

互斥鎖一次只能一個線程擁有互斥鎖,其他線程只有等待。

讀寫鎖

讀寫鎖是共享鎖的一種具體實現。讀寫鎖管理一組鎖,一個是只讀的鎖,一個是寫鎖。

讀鎖可以在沒有寫鎖的時候被多個線程同時持有,而寫鎖是獨占的。寫鎖的優先級要高于讀鎖,一個獲得了讀鎖的線程必須能看到前一個釋放的寫鎖所更新的內容。

讀寫鎖相比于互斥鎖并發程度更高,每次只有一個寫線程,但是同時可以有多個線程并發讀。

8ae9dca8-f28d-11ed-90ce-dac502259ad0.png

在 JDK 中定義了一個讀寫鎖的接口:ReadWriteLock

publicinterfaceReadWriteLock{
/**
*獲取讀鎖
*/
LockreadLock();

/**
*獲取寫鎖
*/
LockwriteLock();
}

ReentrantReadWriteLock 實現了ReadWriteLock接口,具體實現這里不展開,后續會深入源碼解析。

公平鎖和非公平鎖

公平鎖

公平鎖是指多個線程按照申請鎖的順序來獲取鎖,這里類似排隊買票,先來的人先買,后來的人在隊尾排著,這是公平的。

8b01e758-f28d-11ed-90ce-dac502259ad0.png

在 java 中可以通過構造函數初始化公平鎖

/**
*創建一個可重入鎖,true 表示公平鎖,false 表示非公平鎖。默認非公平鎖
*/
Locklock=newReentrantLock(true);

非公平鎖

非公平鎖是指多個線程獲取鎖的順序并不是按照申請鎖的順序,有可能后申請的線程比先申請的線程優先獲取鎖,在高并發環境下,有可能造成優先級翻轉,或者饑餓的狀態(某個線程一直得不到鎖)。

8b124530-f28d-11ed-90ce-dac502259ad0.png

在 java 中 synchronized 關鍵字是非公平鎖,ReentrantLock默認也是非公平鎖。

/**
*創建一個可重入鎖,true 表示公平鎖,false 表示非公平鎖。默認非公平鎖
*/
Locklock=newReentrantLock(false);

可重入鎖

可重入鎖又稱之為遞歸鎖,是指同一個線程在外層方法獲取了鎖,在進入內層方法會自動獲取鎖。

8b2dab04-f28d-11ed-90ce-dac502259ad0.png

對于Java ReentrantLock而言, 他的名字就可以看出是一個可重入鎖。對于Synchronized而言,也是一個可重入鎖。

敲黑板:可重入鎖的一個好處是可一定程度避免死鎖。

以 synchronized 為例,看一下下面的代碼:

publicsynchronizedvoidmehtodA()throwsException{
//Dosomemagictings
mehtodB();
}

publicsynchronizedvoidmehtodB()throwsException{
//Dosomemagictings
}

上面的代碼中 methodA 調用 methodB,如果一個線程調用methodA 已經獲取了鎖再去調用 methodB 就不需要再次獲取鎖了,這就是可重入鎖的特性。如果不是可重入鎖的話,mehtodB 可能不會被當前線程執行,可能造成死鎖。

自旋鎖

自旋鎖是指線程在沒有獲得鎖時不是被直接掛起,而是執行一個忙循環,這個忙循環就是所謂的自旋。

8b526304-f28d-11ed-90ce-dac502259ad0.png

自旋鎖的目的是為了減少線程被掛起的幾率,因為線程的掛起和喚醒也都是耗資源的操作。

如果鎖被另一個線程占用的時間比較長,即使自旋了之后當前線程還是會被掛起,忙循環就會變成浪費系統資源的操作,反而降低了整體性能。因此自旋鎖是不適應鎖占用時間長的并發情況的。

在 Java 中,AtomicInteger 類有自旋的操作,我們看一下代碼:

publicfinalintgetAndAddInt(Objecto,longoffset,intdelta){
intv;
do{
v=getIntVolatile(o,offset);
}while(!compareAndSwapInt(o,offset,v,v+delta));
returnv;
}

CAS 操作如果失敗就會一直循環獲取當前 value 值然后重試。

另外自適應自旋鎖也需要了解一下。

在JDK1.6又引入了自適應自旋,這個就比較智能了,自旋時間不再固定,由前一次在同一個鎖上的自旋時間以及鎖的擁有者的狀態來決定。如果虛擬機認為這次自旋也很有可能再次成功那就會次序較多的時間,如果自旋很少成功,那以后可能就直接省略掉自旋過程,避免浪費處理器資源。

分段鎖

分段鎖 是一種鎖的設計,并不是具體的一種鎖。

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

8b796b98-f28d-11ed-90ce-dac502259ad0.png

在 Java 語言中 CurrentHashMap 底層就用了分段鎖,使用Segment,就可以進行并發使用了。

鎖升級(無鎖|偏向鎖|輕量級鎖|重量級鎖)

JDK1.6 為了提升性能減少獲得鎖和釋放鎖所帶來的消耗,引入了4種鎖的狀態:無鎖、偏向鎖、輕量級鎖和重量級鎖,它會隨著多線程的競爭情況逐漸升級,但不能降級。

無鎖

無鎖狀態其實就是上面講的樂觀鎖,這里不再贅述。

偏向鎖

Java偏向鎖(Biased Locking)是指它會偏向于第一個訪問鎖的線程,如果在運行過程中,只有一個線程訪問加鎖的資源,不存在多線程競爭的情況,那么線程是不需要重復獲取鎖的,這種情況下,就會給線程加一個偏向鎖。

偏向鎖的實現是通過控制對象Mark Word的標志位來實現的,如果當前是可偏向狀態,需要進一步判斷對象頭存儲的線程 ID 是否與當前線程 ID 一致,如果一致直接進入。

輕量級鎖

當線程競爭變得比較激烈時,偏向鎖就會升級為輕量級鎖,輕量級鎖認為雖然競爭是存在的,但是理想情況下競爭的程度很低,通過自旋方式等待上一個線程釋放鎖。

重量級鎖

如果線程并發進一步加劇,線程的自旋超過了一定次數,或者一個線程持有鎖,一個線程在自旋,又來了第三個線程訪問時(反正就是競爭繼續加大了),輕量級鎖就會膨脹為重量級鎖,重量級鎖會使除了此時擁有鎖的線程以外的線程都阻塞。

升級到重量級鎖其實就是互斥鎖了,一個線程拿到鎖,其余線程都會處于阻塞等待狀態。

在 Java 中,synchronized 關鍵字內部實現原理就是鎖升級的過程:無鎖 --> 偏向鎖 --> 輕量級鎖 --> 重量級鎖。這一過程在后續講解 synchronized 關鍵字的原理時會詳細介紹。

鎖優化技術(鎖粗化、鎖消除)

鎖粗化

鎖粗化就是將多個同步塊的數量減少,并將單個同步塊的作用范圍擴大,本質上就是將多次上鎖、解鎖的請求合并為一次同步請求。

舉個例子,一個循環體中有一個代碼同步塊,每次循環都會執行加鎖解鎖操作。

privatestaticfinalObjectLOCK=newObject();

for(inti=0;i

經過鎖粗化后就變成下面這個樣子了:

synchronized(LOCK){
for(inti=0;i

鎖消除

鎖消除是指虛擬機編譯器在運行時檢測到了共享數據沒有競爭的鎖,從而將這些鎖進行消除。

舉個例子讓大家更好理解。

publicStringtest(Strings1,Strings2){
StringBufferstringBuffer=newStringBuffer();
stringBuffer.append(s1);
stringBuffer.append(s2);
returnstringBuffer.toString();
}

上面代碼中有一個 test 方法,主要作用是將字符串 s1 和字符串 s2 串聯起來。

test 方法中三個變量s1, s2, stringBuffer, 它們都是局部變量,局部變量是在棧上的,棧是線程私有的,所以就算有多個線程訪問 test 方法也是線程安全的。

我們都知道 StringBuffer 是線程安全的類,append 方法是同步方法,但是 test 方法本來就是線程安全的,為了提升效率,虛擬機幫我們消除了這些同步鎖,這個過程就被稱為鎖消除。

StringBuffer.class

//append是同步方法
publicsynchronizedStringBufferappend(Stringstr){
toStringCache=null;
super.append(str);
returnthis;
}

一張圖總結:

前面講了 Java 語言中各種各種的鎖,最后再通過六個問題統一總結一下:

8b8c537a-f28d-11ed-90ce-dac502259ad0.png






審核編輯:劉清

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 處理器
    +關注

    關注

    68

    文章

    19265

    瀏覽量

    229671
  • JAVA語言
    +關注

    關注

    0

    文章

    138

    瀏覽量

    20090
  • CAS
    CAS
    +關注

    關注

    0

    文章

    34

    瀏覽量

    15204

原文標題:聊聊Java中那18 把鎖

文章出處:【微信號:芋道源碼,微信公眾號:芋道源碼】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    Java 利用 redis 實現一個分布式服務

    Java 利用 redis 實現一個分布式服務
    發表于 07-05 13:14

    聊聊字符串

    大家好,我是驚覺,今天聊聊字符串。字符串的使用場景非常之多,人機交互和雙機通信都會用到。比如:通過串口向單片機發送指令,以執行操作或配置參數。單片機讀取傳感器數據,數據格式是字符串。一般GPS數據
    發表于 02-28 06:52

    如何給筆記本上一U

    如何給筆記本上一U   數據往往超過筆記本的價值   2010年的今天,筆記本電腦在我們工作的重要性與日聚
    發表于 01-23 11:14 ?1021次閱讀

    聊聊java泛型實現的原理與好處

    取得自己泛型參數的Class類型,C++只能由編譯器推斷在不為人知的地方生成新的類,對于特定的模板參數你只能使用特化。在本文中我主要想聊聊泛型的實現原理和一些高級特性。 泛型基礎 泛型是對Java語言類型系統的一種擴展,有點類似于C++的模板,可以
    發表于 09-27 16:50 ?0次下載

    java數組的三種定義方式_java數組的定義及使用方法(推薦)

    java,數組是一種很常用的工具,本文將介紹來java數組的三種定義方式以及java數組的
    發表于 01-29 09:53 ?3.2w次閱讀

    java學習——java面試【事務、、多線程】資料整理

    本文檔內容介紹了基于java學習java面試【事務、、多線程】資料整理,供參考
    發表于 03-13 13:53 ?0次下載

    java學習——java的反射學習筆記

    本文檔內容介紹了java學習java的反射學習筆記,供參考
    發表于 03-13 14:19 ?0次下載

    如何挑放心

    第一招:買看鑰匙的“牙齒”。牙越多,齒越深,排列越復雜,開啟難度越大,防盜性能越好。第二招:挑論斤稱兩,一比重量二看芯。重量越重,芯質量越好,
    發表于 08-22 11:02 ?300次閱讀

    Java學習路線教程之Java新手必須學習21個技術點詳細資料說明

    Java調用本地接口方法,一般用于C/C++代碼的調用。需要注意的是在java中加載so/dll文件的路徑問題,本身調用接口并不復雜,但是經常在是否加載了所需的本地接口庫花費較多時
    發表于 12-19 15:23 ?19次下載

    如果智能不防鉆 安全一定無法保證

    安全專家提示:1、如果芯不防鉆,那一定不是C級芯。因為國家標準對C級芯對防鉆的要求非常明確,防鉆需要三十分鐘。按這標準,芯如果沒有防鉆功能、沒有防鉆的保護
    發表于 01-17 15:17 ?768次閱讀

    小區業主自制66的門禁系統

    12月16日,遼寧沈陽的皇姑區一小區上了熱搜。 ? 原因竟然是這個小區的業主自制66的門禁系統,被網友譽為“最便宜的門禁系統”。 ? 據報道,該小區之前總有外來車輛進出,停車位被二手車行霸占
    的頭像 發表于 01-06 17:11 ?2817次閱讀

    Java時間戳的使用

    Java時間戳的使用
    的頭像 發表于 11-06 16:04 ?190次閱讀
    <b class='flag-5'>Java</b><b class='flag-5'>中</b>時間戳的使用

    如何使用 Java 原生格式化Instant

    今天我們將聊聊如何在Java一個 Instant 格式化為一個字符串。我們將展示如何使用 Java 原生和第三方庫(如Joda-Time
    的頭像 發表于 10-09 14:51 ?1260次閱讀

    Java redis怎么實現

    Java實現Redis涉及到以下幾個方面:Redis的安裝配置、Redis連接池的使用、Redis數據結構的選擇、實現分布式的幾種方式等。 一、Redis的安裝配置 下載Red
    的頭像 發表于 12-04 10:47 ?1159次閱讀

    java redis處理并發代碼

    在并發編程,一個常見的問題是如何確保多個線程安全地訪問共享資源,避免產生競態條件和數據異常。而Redis作為一種高性能的內存數據庫,可以提供分布式的功能,通過Redis,我們可以有效地解決并發
    的頭像 發表于 12-04 11:04 ?946次閱讀
    主站蜘蛛池模板: 欧美性爱 成人| 91免费精品国自产拍在线可以看| 高清国语自产拍在线| 欧美高清vivoesosexo18| 中文字幕无码他人妻味| 极品内射少妇精品无码视频| 午夜在线视频国产极品片 | 久久国产成人午夜AV影院无码| 小黄文纯肉短篇| 国产福利视频一区二区| 色多多污污在线观看网站| 扒开黑女人p大荫蒂老女人| 女人夜夜春| 99久久e免费热视频百度| 免费国产网站| 97视频免费在线| 美女诱点第6季| 99re1久久热在线播放| 美女露出撒尿的部位| 67194免费入口| 免费一级特黄欧美大片久久网| 777米奇色狠狠俺去啦| 美女扒开屁股让男人桶| 91情国产l精品国产亚洲区| 男人都懂www深夜免费网站| 最近高清日本免费| 毛片手机在线看| 97伦理97伦理2018最新| 牛牛在线精品视频| WWW国产亚洲精品久久久日本| 人妻兽虐曲| 高跟丝袜岳第一次| 洗濯屋H纯肉动漫在线观看| 国产性色AV内射白浆肛交后入| 亚洲第一免费播放区| 交换娇妻呻吟声不停中文字幕| 亚洲一区免费看| 久久中文字幕人妻熟AV女蜜柚M| 7756短视频| 全是肉的高h短篇列车| 国产99热在线观看|