www.久久久久|狼友网站av天堂|精品国产无码a片|一级av色欲av|91在线播放视频|亚洲无码主播在线|国产精品草久在线|明星AV网站在线|污污内射久久一区|婷婷综合视频网站

當(dāng)前位置:首頁(yè) > 公眾號(hào)精選 > 架構(gòu)師社區(qū)
[導(dǎo)讀]本篇主要內(nèi)容如下: 本篇主要內(nèi)容 本篇文章已收納到我的Java在線文檔、 Github 我的SpringCloud實(shí)戰(zhàn)項(xiàng)目持續(xù)更新中 幫你總結(jié)好的鎖: 序號(hào) 鎖名稱 應(yīng)用 1 樂觀鎖 CAS 2 悲觀鎖 synchronized、vector、hashtable 3 自旋鎖 CAS 4 可重入鎖 synchronized、Reentr

本篇主要內(nèi)容如下:

24張圖帶你徹底理解Java中的21種鎖 本篇主要內(nèi)容

本篇文章已收納到我的Java在線文檔、 Github

我的SpringCloud實(shí)戰(zhàn)項(xiàng)目持續(xù)更新中

幫你總結(jié)好的鎖:

序號(hào) 鎖名稱 應(yīng)用
1 樂觀鎖 CAS
2 悲觀鎖 synchronized、vector、hashtable
3 自旋鎖 CAS
4 可重入鎖 synchronized、Reentrantlock、Lock
5 讀寫鎖 ReentrantReadWriteLock,CopyOnWriteArrayList、CopyOnWriteArraySet
6 公平鎖 Reentrantlock(true)
7 非公平鎖 synchronized、reentrantlock(false)
8 共享鎖 ReentrantReadWriteLock中讀鎖
9 獨(dú)占鎖 synchronized、vector、hashtable、ReentrantReadWriteLock中寫鎖
10 重量級(jí)鎖 synchronized
11 輕量級(jí)鎖 鎖優(yōu)化技術(shù)
12 偏向鎖 鎖優(yōu)化技術(shù)
13 分段鎖 concurrentHashMap
14 互斥鎖 synchronized
15 同步鎖 synchronized
16 死鎖 相互請(qǐng)求對(duì)方的資源
17 鎖粗化 鎖優(yōu)化技術(shù)
18 鎖消除 鎖優(yōu)化技術(shù)

1、樂觀鎖

24張圖帶你徹底理解Java中的21種鎖 樂觀鎖

樂觀鎖是一種樂觀思想,假定當(dāng)前環(huán)境是讀多寫少,遇到并發(fā)寫的概率比較低,讀數(shù)據(jù)時(shí)認(rèn)為別的線程不會(huì)正在進(jìn)行修改(所以沒有上鎖)。寫數(shù)據(jù)時(shí),判斷當(dāng)前 與期望值是否相同,如果相同則進(jìn)行更新(更新期間加鎖,保證是原子性的)。

Java中的樂觀鎖: CAS,比較并替換,比較當(dāng)前值(主內(nèi)存中的值),與預(yù)期值(當(dāng)前線程中的值,主內(nèi)存中值的一份拷貝)是否一樣,一樣則更新,否則繼續(xù)進(jìn)行CAS操作。

如上圖所示,可以同時(shí)進(jìn)行讀操作,讀的時(shí)候其他線程不能進(jìn)行寫操作。

2、悲觀鎖

24張圖帶你徹底理解Java中的21種鎖 悲觀鎖

悲觀鎖是一種悲觀思想,即認(rèn)為寫多讀少,遇到并發(fā)寫的可能性高,每次去拿數(shù)據(jù)的時(shí)候都認(rèn)為其他線程會(huì)修改,所以每次讀寫數(shù)據(jù)都會(huì)認(rèn)為其他線程會(huì)修改,所以每次讀寫數(shù)據(jù)時(shí)都會(huì)上鎖。其他線程想要讀寫這個(gè)數(shù)據(jù)時(shí),會(huì)被這個(gè)線程block,直到這個(gè)線程釋放鎖然后其他線程獲取到鎖。

Java中的悲觀鎖: synchronized修飾的方法和方法塊、ReentrantLock。

如上圖所示,只能有一個(gè)線程進(jìn)行讀操作或者寫操作,其他線程的讀寫操作均不能進(jìn)行。

3、自旋鎖

24張圖帶你徹底理解Java中的21種鎖 mark

自旋鎖是一種技術(shù): 為了讓線程等待,我們只須讓線程執(zhí)行一個(gè)忙循環(huán)(自旋)。

現(xiàn)在絕大多數(shù)的個(gè)人電腦和服務(wù)器都是多路(核)處理器系統(tǒng),如果物理機(jī)器有一個(gè)以上的處理器或者處理器核心,能讓兩個(gè)或以上的線程同時(shí)并行執(zhí)行,就可以讓后面請(qǐng)求鎖的那個(gè)線程“稍等一會(huì)”,但不放棄處理器的執(zhí)行時(shí)間,看看持有鎖的線程是否很快就會(huì)釋放鎖。

自旋鎖的優(yōu)點(diǎn): 避免了線程切換的開銷。掛起線程和恢復(fù)線程的操作都需要轉(zhuǎn)入內(nèi)核態(tài)中完成,這些操作給Java虛擬機(jī)的并發(fā)性能帶來了很大的壓力。

自旋鎖的缺點(diǎn): 占用處理器的時(shí)間,如果占用的時(shí)間很長(zhǎng),會(huì)白白消耗處理器資源,而不會(huì)做任何有價(jià)值的工作,帶來性能的浪費(fèi)。因此自旋等待的時(shí)間必須有一定的限度,如果自旋超過了限定的次數(shù)仍然沒有成功獲得鎖,就應(yīng)當(dāng)使用傳統(tǒng)的方式去掛起線程。

自旋次數(shù)默認(rèn)值:10次,可以使用參數(shù)-XX:PreBlockSpin來自行更改。

自適應(yīng)自旋: 自適應(yīng)意味著自旋的時(shí)間不再是固定的,而是由前一次在同一個(gè)鎖上的自旋時(shí)間及鎖的擁有者的狀態(tài)來決定的。有了自適應(yīng)自旋,隨著程序運(yùn)行時(shí)間的增長(zhǎng)及性能監(jiān)控信息的不斷完善,虛擬機(jī)對(duì)程序鎖的狀態(tài)預(yù)測(cè)就會(huì)越來越精準(zhǔn)。

Java中的自旋鎖: CAS操作中的比較操作失敗后的自旋等待。

4、可重入鎖(遞歸鎖)

24張圖帶你徹底理解Java中的21種鎖 可重入鎖

可重入鎖是一種技術(shù): 任意線程在獲取到鎖之后能夠再次獲取該鎖而不會(huì)被鎖所阻塞。

可重入鎖的原理: 通過組合自定義同步器來實(shí)現(xiàn)鎖的獲取與釋放。

  • 再次獲取鎖:識(shí)別獲取鎖的線程是否為當(dāng)前占據(jù)鎖的線程,如果是,則再次成功獲取。獲取鎖后,進(jìn)行計(jì)數(shù)自增,
  • 釋放鎖:釋放鎖時(shí),進(jìn)行計(jì)數(shù)自減。

Java中的可重入鎖: ReentrantLock、synchronized修飾的方法或代碼段。

可重入鎖的作用: 避免死鎖。

面試題1: 可重入鎖如果加了兩把,但是只釋放了一把會(huì)出現(xiàn)什么問題?

答:程序卡死,線程不能出來,也就是說我們申請(qǐng)了幾把鎖,就需要釋放幾把鎖。

面試題2: 如果只加了一把鎖,釋放兩次會(huì)出現(xiàn)什么問題?

答:會(huì)報(bào)錯(cuò),java.lang.IllegalMonitorStateException。

5、讀寫鎖

讀寫鎖是一種技術(shù): 通過ReentrantReadWriteLock類來實(shí)現(xiàn)。為了提高性能, Java 提供了讀寫鎖,在讀的地方使用讀鎖,在寫的地方使用寫鎖,靈活控制,如果沒有寫鎖的情況下,讀是無(wú)阻塞的,在一定程度上提高了程序的執(zhí)行效率。讀寫鎖分為讀鎖和寫鎖,多個(gè)讀鎖不互斥,讀鎖與寫鎖互斥,這是由 jvm 自己控制的。

讀鎖: 允許多個(gè)線程獲取讀鎖,同時(shí)訪問同一個(gè)資源。

24張圖帶你徹底理解Java中的21種鎖 讀鎖

寫鎖: 只允許一個(gè)線程獲取寫鎖,不允許同時(shí)訪問同一個(gè)資源。

24張圖帶你徹底理解Java中的21種鎖 寫鎖

如何使用:

/**
* 創(chuàng)建一個(gè)讀寫鎖
* 它是一個(gè)讀寫融為一體的鎖,在使用的時(shí)候,需要轉(zhuǎn)換
*/ private ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();

獲取讀鎖和釋放讀鎖

// 獲取讀鎖 rwLock.readLock().lock(); // 釋放讀鎖 rwLock.readLock().unlock();

獲取寫鎖和釋放寫鎖

// 創(chuàng)建一個(gè)寫鎖 rwLock.writeLock().lock(); // 寫鎖 釋放 rwLock.writeLock().unlock();

Java中的讀寫鎖:ReentrantReadWriteLock

6、公平鎖

24張圖帶你徹底理解Java中的21種鎖 公平鎖

公平鎖是一種思想: 多個(gè)線程按照申請(qǐng)鎖的順序來獲取鎖。在并發(fā)環(huán)境中,每個(gè)線程會(huì)先查看此鎖維護(hù)的等待隊(duì)列,如果當(dāng)前等待隊(duì)列為空,則占有鎖,如果等待隊(duì)列不為空,則加入到等待隊(duì)列的末尾,按照FIFO的原則從隊(duì)列中拿到線程,然后占有鎖。

7、非公平鎖

24張圖帶你徹底理解Java中的21種鎖 非公平鎖

非公平鎖是一種思想: 線程嘗試獲取鎖,如果獲取不到,則再采用公平鎖的方式。多個(gè)線程獲取鎖的順序,不是按照先到先得的順序,有可能后申請(qǐng)鎖的線程比先申請(qǐng)的線程優(yōu)先獲取鎖。

優(yōu)點(diǎn): 非公平鎖的性能高于公平鎖。

缺點(diǎn): 有可能造成線程饑餓(某個(gè)線程很長(zhǎng)一段時(shí)間獲取不到鎖)

Java中的非公平鎖:synchronized是非公平鎖,ReentrantLock通過構(gòu)造函數(shù)指定該鎖是公平的還是非公平的,默認(rèn)是非公平的。

8、共享鎖

24張圖帶你徹底理解Java中的21種鎖 共享鎖

共享鎖是一種思想: 可以有多個(gè)線程獲取讀鎖,以共享的方式持有鎖。和樂觀鎖、讀寫鎖同義。

Java中用到的共享鎖: ReentrantReadWriteLock。

9、獨(dú)占鎖

24張圖帶你徹底理解Java中的21種鎖 獨(dú)占鎖

獨(dú)占鎖是一種思想: 只能有一個(gè)線程獲取鎖,以獨(dú)占的方式持有鎖。和悲觀鎖、互斥鎖同義。

Java中用到的獨(dú)占鎖: synchronized,ReentrantLock

10、重量級(jí)鎖

24張圖帶你徹底理解Java中的21種鎖 重量級(jí)鎖

重量級(jí)鎖是一種稱謂: synchronized是通過對(duì)象內(nèi)部的一個(gè)叫做監(jiān)視器鎖(monitor)來實(shí)現(xiàn)的,監(jiān)視器鎖本身依賴底層的操作系統(tǒng)的 Mutex Lock來實(shí)現(xiàn)。操作系統(tǒng)實(shí)現(xiàn)線程的切換需要從用戶態(tài)切換到核心態(tài),成本非常高。這種依賴于操作系統(tǒng) Mutex Lock來實(shí)現(xiàn)的鎖稱為重量級(jí)鎖。為了優(yōu)化synchonized,引入了輕量級(jí)鎖,偏向鎖。

Java中的重量級(jí)鎖: synchronized

11、輕量級(jí)鎖

24張圖帶你徹底理解Java中的21種鎖 輕量級(jí)鎖

輕量級(jí)鎖是JDK6時(shí)加入的一種鎖優(yōu)化機(jī)制: 輕量級(jí)鎖是在無(wú)競(jìng)爭(zhēng)的情況下使用CAS操作去消除同步使用的互斥量。輕量級(jí)是相對(duì)于使用操作系統(tǒng)互斥量來實(shí)現(xiàn)的重量級(jí)鎖而言的。輕量級(jí)鎖在沒有多線程競(jìng)爭(zhēng)的前提下,減少傳統(tǒng)的重量級(jí)鎖使用操作系統(tǒng)互斥量產(chǎn)生的性能消耗。如果出現(xiàn)兩條以上的線程爭(zhēng)用同一個(gè)鎖的情況,那輕量級(jí)鎖將不會(huì)有效,必須膨脹為重量級(jí)鎖。

優(yōu)點(diǎn): 如果沒有競(jìng)爭(zhēng),通過CAS操作成功避免了使用互斥量的開銷。

缺點(diǎn): 如果存在競(jìng)爭(zhēng),除了互斥量本身的開銷外,還額外產(chǎn)生了CAS操作的開銷,因此在有競(jìng)爭(zhēng)的情況下,輕量級(jí)鎖比傳統(tǒng)的重量級(jí)鎖更慢。

12、偏向鎖

24張圖帶你徹底理解Java中的21種鎖 偏向鎖

偏向鎖是JDK6時(shí)加入的一種鎖優(yōu)化機(jī)制: 在無(wú)競(jìng)爭(zhēng)的情況下把整個(gè)同步都消除掉,連CAS操作都不去做了。偏是指偏心,它的意思是這個(gè)鎖會(huì)偏向于第一個(gè)獲得它的線程,如果在接下來的執(zhí)行過程中,該鎖一直沒有被其他的線程獲取,則持有偏向鎖的線程將永遠(yuǎn)不需要再進(jìn)行同步。持有偏向鎖的線程以后每次進(jìn)入這個(gè)鎖相關(guān)的同步塊時(shí),虛擬機(jī)都可以不再進(jìn)行任何同步操作(例如加鎖、解鎖及對(duì)Mark Word的更新操作等)。

優(yōu)點(diǎn): 把整個(gè)同步都消除掉,連CAS操作都不去做了,優(yōu)于輕量級(jí)鎖。

缺點(diǎn): 如果程序中大多數(shù)的鎖都總是被多個(gè)不同的線程訪問,那偏向鎖就是多余的。

13、分段鎖

24張圖帶你徹底理解Java中的21種鎖 分段鎖

分段鎖是一種機(jī)制: 最好的例子來說明分段鎖是ConcurrentHashMap。ConcurrentHashMap原理:它內(nèi)部細(xì)分了若干個(gè)小的 HashMap,稱之為段(Segment)。默認(rèn)情況下一個(gè) ConcurrentHashMap 被進(jìn)一步細(xì)分為 16 個(gè)段,既就是鎖的并發(fā)度。如果需要在 ConcurrentHashMap 添加一項(xiàng)key-value,并不是將整個(gè) HashMap 加鎖,而是首先根據(jù) hashcode 得到該key-value應(yīng)該存放在哪個(gè)段中,然后對(duì)該段加鎖,并完成 put 操作。在多線程環(huán)境中,如果多個(gè)線程同時(shí)進(jìn)行put操作,只要被加入的key-value不存放在同一個(gè)段中,則線程間可以做到真正的并行。

線程安全:ConcurrentHashMap 是一個(gè) Segment 數(shù)組, Segment 通過繼承ReentrantLock 來進(jìn)行加鎖,所以每次需要加鎖的操作鎖住的是一個(gè) segment,這樣只要保證每個(gè) Segment 是線程安全的,也就實(shí)現(xiàn)了全局的線程安全

14、互斥鎖

24張圖帶你徹底理解Java中的21種鎖 互斥鎖

互斥鎖與悲觀鎖、獨(dú)占鎖同義,表示某個(gè)資源只能被一個(gè)線程訪問,其他線程不能訪問。

  • 讀-讀互斥
  • 讀-寫互斥
  • 寫-讀互斥
  • 寫-寫互斥

Java中的同步鎖: synchronized

15、同步鎖

24張圖帶你徹底理解Java中的21種鎖 同步鎖

同步鎖與互斥鎖同義,表示并發(fā)執(zhí)行的多個(gè)線程,在同一時(shí)間內(nèi)只允許一個(gè)線程訪問共享數(shù)據(jù)。

Java中的同步鎖: synchronized

16、死鎖

24張圖帶你徹底理解Java中的21種鎖 死鎖

死鎖是一種現(xiàn)象:如線程A持有資源x,線程B持有資源y,線程A等待線程B釋放資源y,線程B等待線程A釋放資源x,兩個(gè)線程都不釋放自己持有的資源,則兩個(gè)線程都獲取不到對(duì)方的資源,就會(huì)造成死鎖。

Java中的死鎖不能自行打破,所以線程死鎖后,線程不能進(jìn)行響應(yīng)。所以一定要注意程序的并發(fā)場(chǎng)景,避免造成死鎖。

17、鎖粗化

24張圖帶你徹底理解Java中的21種鎖 鎖粗化

鎖粗化是一種優(yōu)化技術(shù): 如果一系列的連續(xù)操作都對(duì)同一個(gè)對(duì)象反復(fù)加鎖和解鎖,甚至加鎖操作都是出現(xiàn)在循環(huán)體體之中,就算真的沒有線程競(jìng)爭(zhēng),頻繁地進(jìn)行互斥同步操作將會(huì)導(dǎo)致不必要的性能損耗,所以就采取了一種方案:把加鎖的范圍擴(kuò)展(粗化)到整個(gè)操作序列的外部,這樣加鎖解鎖的頻率就會(huì)大大降低,從而減少了性能損耗。

18、鎖消除

24張圖帶你徹底理解Java中的21種鎖 鎖消除

鎖消除是一種優(yōu)化技術(shù): 就是把鎖干掉。當(dāng)Java虛擬機(jī)運(yùn)行時(shí)發(fā)現(xiàn)有些共享數(shù)據(jù)不會(huì)被線程競(jìng)爭(zhēng)時(shí)就可以進(jìn)行鎖消除。

那如何判斷共享數(shù)據(jù)不會(huì)被線程競(jìng)爭(zhēng)?

利用逃逸分析技術(shù):分析對(duì)象的作用域,如果對(duì)象在A方法中定義后,被作為參數(shù)傳遞到B方法中,則稱為方法逃逸;如果被其他線程訪問,則稱為線程逃逸。

在堆上的某個(gè)數(shù)據(jù)不會(huì)逃逸出去被其他線程訪問到,就可以把它當(dāng)作棧上數(shù)據(jù)對(duì)待,認(rèn)為它是線程私有的,同步加鎖就不需要了。

19、synchronized

24張圖帶你徹底理解Java中的21種鎖 synchronized

synchronized是Java中的關(guān)鍵字:用來修飾方法、對(duì)象實(shí)例。屬于獨(dú)占鎖、悲觀鎖、可重入鎖、非公平鎖。

  • 1.作用于實(shí)例方法時(shí),鎖住的是對(duì)象的實(shí)例(this);

  • 2.當(dāng)作用于靜態(tài)方法時(shí),鎖住的是 Class類,相當(dāng)于類的一個(gè)全局鎖, 會(huì)鎖所有調(diào)用該方法的線程;

  • 3.synchronized 作用于一個(gè)非 NULL的對(duì)象實(shí)例時(shí),鎖住的是所有以該對(duì)象為鎖的代碼塊。它有多個(gè)隊(duì)列,當(dāng)多個(gè)線程一起訪問某個(gè)對(duì)象監(jiān)視器的時(shí)候,對(duì)象監(jiān)視器會(huì)將這些線程存儲(chǔ)在不同的容器中。

每個(gè)對(duì)象都有個(gè) monitor 對(duì)象, 加鎖就是在競(jìng)爭(zhēng) monitor 對(duì)象,代碼塊加鎖是在代碼塊前后分別加上 monitorenter 和 monitorexit 指令來實(shí)現(xiàn)的,方法加鎖是通過一個(gè)標(biāo)記位來判斷的。

20、Lock和synchronized的區(qū)別

24張圖帶你徹底理解Java中的21種鎖 自動(dòng)擋和手動(dòng)擋的區(qū)別

Lock: 是Java中的接口,可重入鎖、悲觀鎖、獨(dú)占鎖、互斥鎖、同步鎖。

  • 1.Lock需要手動(dòng)獲取鎖和釋放鎖。就好比自動(dòng)擋和手動(dòng)擋的區(qū)別
  • 2.Lock 是一個(gè)接口,而 synchronized 是 Java 中的關(guān)鍵字, synchronized 是內(nèi)置的語(yǔ)言實(shí)現(xiàn)。
  • 3.synchronized 在發(fā)生異常時(shí),會(huì)自動(dòng)釋放線程占有的鎖,因此不會(huì)導(dǎo)致死鎖現(xiàn)象發(fā)生;而 Lock 在發(fā)生異常時(shí),如果沒有主動(dòng)通過 unLock()去釋放鎖,則很可能造成死鎖現(xiàn)象,因此使用 Lock 時(shí)需要在 finally 塊中釋放鎖。
  • 4.Lock 可以讓等待鎖的線程響應(yīng)中斷,而 synchronized 卻不行,使用 synchronized 時(shí),等待的線程會(huì)一直等待下去,不能夠響應(yīng)中斷。
  • 5.通過 Lock 可以知道有沒有成功獲取鎖,而 synchronized 卻無(wú)法辦到。
  • 6.Lock 可以通過實(shí)現(xiàn)讀寫鎖提高多個(gè)線程進(jìn)行讀操作的效率。

synchronized的優(yōu)勢(shì):

  • 足夠清晰簡(jiǎn)單,只需要基礎(chǔ)的同步功能時(shí),用synchronized。
  • Lock應(yīng)該確保在finally塊中釋放鎖。如果使用synchronized,JVM確保即使出現(xiàn)異常,鎖也能被自動(dòng)釋放。
  • 使用Lock時(shí),Java虛擬機(jī)很難得知哪些鎖對(duì)象是由特定線程鎖持有的。

21、ReentrantLock 和synchronized的區(qū)別

24張圖帶你徹底理解Java中的21種鎖 Lock、ReentrantLock、shnchronzied

ReentrantLock是Java中的類 : 繼承了Lock類,可重入鎖、悲觀鎖、獨(dú)占鎖、互斥鎖、同步鎖。

劃重點(diǎn)

相同點(diǎn):

  • 1.主要解決共享變量如何安全訪問的問題
  • 2.都是可重入鎖,也叫做遞歸鎖,同一線程可以多次獲得同一個(gè)鎖,
  • 3.保證了線程安全的兩大特性:可見性、原子性。

不同點(diǎn):

  • 1.ReentrantLock 就像手動(dòng)汽車,需要顯示的調(diào)用lock和unlock方法, synchronized 隱式獲得釋放鎖。

  • 2.ReentrantLock 可響應(yīng)中斷, synchronized 是不可以響應(yīng)中斷的,ReentrantLock 為處理鎖的不可用性提供了更高的靈活性

  • 3.ReentrantLock 是 API 級(jí)別的, synchronized 是 JVM 級(jí)別的

  • 4.ReentrantLock 可以實(shí)現(xiàn)公平鎖、非公平鎖,默認(rèn)非公平鎖,synchronized 是非公平鎖,且不可更改。

  • 5.ReentrantLock 通過 Condition 可以綁定多個(gè)條件



免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。文章僅代表作者個(gè)人觀點(diǎn),不代表本平臺(tái)立場(chǎng),如有問題,請(qǐng)聯(lián)系我們,謝謝!

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
關(guān)閉
關(guān)閉