成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

詳解Java鎖機(jī)制:看完你就明白的鎖系列之鎖的狀態(tài)

開發(fā) 后端
看完你就會知道,線程如果鎖住了某個資源,致使其他線程無法訪問的這種鎖被稱為悲觀鎖,相反,線程不鎖住資源的鎖被稱為樂觀鎖,而自旋鎖是基于 CAS 機(jī)制實(shí)現(xiàn)的,CAS又是樂觀鎖的一種實(shí)現(xiàn),那么對于鎖來說,多個線程同步訪問某個資源的流程細(xì)節(jié)是否一樣呢?

 看完你就會知道,線程如果鎖住了某個資源,致使其他線程無法訪問的這種鎖被稱為悲觀鎖,相反,線程不鎖住資源的鎖被稱為樂觀鎖,而自旋鎖是基于 CAS 機(jī)制實(shí)現(xiàn)的,CAS又是樂觀鎖的一種實(shí)現(xiàn),那么對于鎖來說,多個線程同步訪問某個資源的流程細(xì)節(jié)是否一樣呢?換句話說,在多線程同步訪問某個資源時,鎖的狀態(tài)會如何變化呢?本篇文章來探討一下。

[[279418]]

鎖狀態(tài)的分類

Java 語言專門針對 synchronized 關(guān)鍵字設(shè)置了四種狀態(tài),它們分別是:無鎖、偏向鎖、輕量級鎖和重量級鎖,但是在了解這些鎖之前還需要先了解一下 Java 對象頭和 Monitor。

Java 對象頭

我們知道 synchronized 是悲觀鎖,在操作同步之前需要給資源加鎖,這把鎖就是對象頭里面的,而Java 對象頭又是什么呢?我們以 Hotspot 虛擬機(jī)為例,Hopspot 對象頭主要包括兩部分?jǐn)?shù)據(jù):Mark Word(標(biāo)記字段) 和 Klass Pointer(類型指針)。

Mark Word:默認(rèn)存儲對象的HashCode,分代年齡和鎖標(biāo)志位信息。這些信息都是與對象自身定義無關(guān)的數(shù)據(jù),所以Mark Word被設(shè)計(jì)成一個非固定的數(shù)據(jù)結(jié)構(gòu)以便在極小的空間內(nèi)存存儲盡量多的數(shù)據(jù)。它會根據(jù)對象的狀態(tài)復(fù)用自己的存儲空間,也就是說在運(yùn)行期間Mark Word里存儲的數(shù)據(jù)會隨著鎖標(biāo)志位的變化而變化。

Klass Point:對象指向它的類元數(shù)據(jù)的指針,虛擬機(jī)通過這個指針來確定這個對象是哪個類的實(shí)例。

在32位虛擬機(jī)和64位虛擬機(jī)的 Mark Word 所占用的字節(jié)大小不一樣,32位虛擬機(jī)的 Mark Word 和 Klass Pointer 分別占用 32bits 的字節(jié),而 64位虛擬機(jī)的 Mark Word 和 Klass Pointer 占用了64bits 的字節(jié),下面我們以 32位虛擬機(jī)為例,來看一下其 Mark Word 的字節(jié)具體是如何分配的

 

詳解Java鎖機(jī)制:看完你就明白的鎖系列之鎖的狀態(tài)

 

 

詳解Java鎖機(jī)制:看完你就明白的鎖系列之鎖的狀態(tài)

 

用中文翻譯過來就是

 

詳解Java鎖機(jī)制:看完你就明白的鎖系列之鎖的狀態(tài)

 

  • 無狀態(tài)也就是無鎖的時候,對象頭開辟 25bit 的空間用來存儲對象的 hashcode ,4bit 用于存放分代年齡,1bit 用來存放是否偏向鎖的標(biāo)識位,2bit 用來存放鎖標(biāo)識位為01
  • 偏向鎖 中劃分更細(xì),還是開辟25bit 的空間,其中23bit 用來存放線程ID,2bit 用來存放 epoch,4bit 存放分代年齡,1bit 存放是否偏向鎖標(biāo)識, 0表示無鎖,1表示偏向鎖,鎖的標(biāo)識位還是01
  • 輕量級鎖中直接開辟 30bit 的空間存放指向棧中鎖記錄的指針,2bit 存放鎖的標(biāo)志位,其標(biāo)志位為00
  • 重量級鎖中和輕量級鎖一樣,30bit 的空間用來存放指向重量級鎖的指針,2bit 存放鎖的標(biāo)識位,為11
  • GC標(biāo)記開辟30bit 的內(nèi)存空間卻沒有占用,2bit 空間存放鎖標(biāo)志位為11。

其中無鎖和偏向鎖的鎖標(biāo)志位都是01,只是在前面的1bit區(qū)分了這是無鎖狀態(tài)還是偏向鎖狀態(tài)。

關(guān)于為什么這么分配的內(nèi)存,我們可以從 OpenJDK 中的markOop.hpp類中的枚舉窺出端倪

 

詳解Java鎖機(jī)制:看完你就明白的鎖系列之鎖的狀態(tài)

 

來解釋一下

  • age_bits 就是我們說的分代回收的標(biāo)識,占用4字節(jié)
  • lock_bits 是鎖的標(biāo)志位,占用2個字節(jié)
  • biased_lock_bits 是是否偏向鎖的標(biāo)識,占用1個字節(jié)
  • max_hash_bits 是針對無鎖計(jì)算的hashcode 占用字節(jié)數(shù)量,如果是32位虛擬機(jī),就是 32 - 4 - 2 -1 = 25 byte,如果是64 位虛擬機(jī),64 - 4 - 2 - 1 = 57 byte,但是會有 25 字節(jié)未使用,所以64位的 hashcode 占用 31 byte
  • hash_bits 是針對 64 位虛擬機(jī)來說,如果最大字節(jié)數(shù)大于 31,則取31,否則取真實(shí)的字節(jié)數(shù)
  • cms_bits 我覺得應(yīng)該是不是64位虛擬機(jī)就占用 0 byte,是64位就占用 1byte
  • epoch_bits 就是 epoch 所占用的字節(jié)大小,2字節(jié)。

Synchronized鎖

synchronized用的鎖是存在Java對象頭里的。

JVM基于進(jìn)入和退出 Monitor 對象來實(shí)現(xiàn)方法同步和代碼塊同步。代碼塊同步是使用 monitorenter 和 monitorexit 指令實(shí)現(xiàn)的,monitorenter 指令是在編譯后插入到同步代碼塊的開始位置,而 monitorexit 是插入到方法結(jié)束處和異常處。任何對象都有一個 monitor 與之關(guān)聯(lián),當(dāng)且一個 monitor 被持有后,它將處于鎖定狀態(tài)。

根據(jù)虛擬機(jī)規(guī)范的要求,在執(zhí)行 monitorenter 指令時,首先要去嘗試獲取對象的鎖,如果這個對象沒被鎖定,或者當(dāng)前線程已經(jīng)擁有了那個對象的鎖,把鎖的計(jì)數(shù)器加1,相應(yīng)地,在執(zhí)行 monitorexit 指令時會將鎖計(jì)數(shù)器減1,當(dāng)計(jì)數(shù)器被減到0時,鎖就釋放了。如果獲取對象鎖失敗了,那當(dāng)前線程就要阻塞等待,直到對象鎖被另一個線程釋放為止。

Monitor

Synchronized是通過對象內(nèi)部的一個叫做監(jiān)視器鎖(monitor)來實(shí)現(xiàn)的,監(jiān)視器鎖本質(zhì)又是依賴于底層的操作系統(tǒng)的 Mutex Lock(互斥鎖)來實(shí)現(xiàn)的。而操作系統(tǒng)實(shí)現(xiàn)線程之間的切換需要從用戶態(tài)轉(zhuǎn)換到核心態(tài),這個成本非常高,狀態(tài)之間的轉(zhuǎn)換需要相對比較長的時間,這就是為什么 Synchronized 效率低的原因。因此,這種依賴于操作系統(tǒng) Mutex Lock 所實(shí)現(xiàn)的鎖我們稱之為重量級鎖。

Java SE 1.6為了減少獲得鎖和釋放鎖帶來的性能消耗,引入了偏向鎖和輕量級鎖:鎖一共有4種狀態(tài),級別從低到高依次是:無鎖狀態(tài)、偏向鎖狀態(tài)、輕量級鎖狀態(tài)和重量級鎖狀態(tài)。鎖可以升級但不能降級。

所以鎖的狀態(tài)總共有四種:無鎖狀態(tài)、偏向鎖、輕量級鎖和重量級鎖。隨著鎖的競爭,鎖可以從偏向鎖升級到輕量級鎖,再升級的重量級鎖(但是鎖的升級是單向的,也就是說只能從低到高升級,不會出現(xiàn)鎖的降級)。JDK 1.6中默認(rèn)是開啟偏向鎖和輕量級鎖的,我們也可以通過-XX:-UseBiasedLocking=false來禁用偏向鎖。

鎖的分類及其解釋

無鎖

無鎖狀態(tài),無鎖即沒有對資源進(jìn)行鎖定,所有的線程都可以對同一個資源進(jìn)行訪問,但是只有一個線程能夠成功修改資源。

無鎖的特點(diǎn)就是在循環(huán)內(nèi)進(jìn)行修改操作,線程會不斷的嘗試修改共享資源,直到能夠成功修改資源并退出,在此過程中沒有出現(xiàn)沖突的發(fā)生,這很像我們在之前文章中介紹的 CAS 實(shí)現(xiàn),CAS 的原理和應(yīng)用就是無鎖的實(shí)現(xiàn)。無鎖無法全面代替有鎖,但無鎖在某些場合下的性能是非常高的。

偏向鎖

Hotspot 的作者經(jīng)過研究發(fā)現(xiàn),大多數(shù)情況下,鎖不僅不存在多線程競爭,還存在鎖由同一線程多次獲得的情況,偏向鎖就是在這種情況下出現(xiàn)的,它的出現(xiàn)是為了解決只有在一個線程執(zhí)行同步時提高性能。

可以從對象頭的分配中看到,偏向鎖要比無鎖多了線程ID 和 epoch,當(dāng)一個線程訪問同步代碼塊并獲取鎖時,會在對象頭和棧幀的記錄中存儲線程的ID,等到下一次線程在進(jìn)入和退出同步代碼塊時就不需要進(jìn)行 CAS 操作進(jìn)行加鎖和解鎖,只需要簡單判斷一下對象頭的 Mark Word 中是否存儲著指向當(dāng)前線程的線程ID,判斷的標(biāo)志當(dāng)然是根據(jù)鎖的標(biāo)志位來判斷的。

偏向鎖的獲取過程

  1. 訪問 Mark Word 中偏向鎖的標(biāo)志是否設(shè)置成 1,鎖的標(biāo)志位是否是 01 --- 確認(rèn)為可偏向狀態(tài)。
  2. 如果確認(rèn)為可偏向狀態(tài),判斷當(dāng)前線程id 和 對象頭中存儲的線程 ID 是否一致,如果一致的話,則執(zhí)行步驟5,如果不一致,進(jìn)入步驟3
  3. 如果當(dāng)前線程ID 與對象頭中存儲的線程ID 不一致的話,則通過 CAS 操作來競爭獲取鎖。如果競爭成功,則將 Mark Word 中的線程ID 修改為當(dāng)前線程ID,然后執(zhí)行步驟5,如果不一致,則執(zhí)行步驟4
  4. 如果 CAS 獲取偏向鎖失敗,則表示有競爭(CAS 獲取偏向鎖失敗則表明至少有其他線程曾經(jīng)獲取過偏向鎖,因?yàn)榫€程不會主動釋放偏向鎖)。當(dāng)?shù)竭_(dá)全局安全點(diǎn)(SafePoint)時,會首先暫停擁有偏向鎖的線程,然后檢查持有偏向鎖的線程是否存活(因?yàn)榭赡艹钟衅蜴i的線程已經(jīng)執(zhí)行完畢,但是該線程并不會主動去釋放偏向鎖),如果線程不處于活動狀態(tài),則將對象頭置為無鎖狀態(tài)(標(biāo)志位為01),然后重新偏向新的線程;如果線程仍然活著,撤銷偏向鎖后升級到輕量級鎖的狀態(tài)(標(biāo)志位為00),此時輕量級鎖由原持有偏向鎖的線程持有,繼續(xù)執(zhí)行其同步代碼,而正在競爭的線程會進(jìn)入自旋等待獲得該輕量級鎖。
  5. 執(zhí)行同步代碼

偏向鎖的釋放過程

偏向鎖的釋放過程可以參考上述的步驟4 ,偏向鎖在遇到其他線程競爭鎖時,持有偏向鎖的線程才會釋放鎖,線程不會主動釋放偏向鎖。偏向鎖的撤銷,需要等待全局安全點(diǎn)(在這個時間點(diǎn)上沒有字節(jié)碼正在執(zhí)行),它會首先暫停擁有偏向鎖的線程,判斷鎖是否處于被鎖定狀態(tài),撤銷偏向鎖后恢復(fù)到未鎖定(標(biāo)志位為01)或輕量級鎖(標(biāo)志位為00)的狀態(tài)。

關(guān)閉偏向鎖

偏向鎖在Java 6 和Java 7 里是默認(rèn)啟用的。由于偏向鎖是為了在只有一個線程執(zhí)行同步塊時提高性能,如果你確定應(yīng)用程序里所有的鎖通常情況下處于競爭狀態(tài),可以通過JVM參數(shù)關(guān)閉偏向鎖:-XX:-UseBiasedLocking=false,那么程序默認(rèn)會進(jìn)入輕量級鎖狀態(tài)。

關(guān)于 epoch

真正理解 epoch 的概念比較復(fù)雜,這里簡單理解,就是 epoch 的值可以作為一種檢測偏向鎖有效性的時間戳

輕量級鎖

輕量級鎖是指當(dāng)前鎖是偏向鎖的時候,被另外的線程所訪問,那么偏向鎖就會升級為輕量級鎖,其他線程會通過自旋的形式嘗試獲取鎖,不會阻塞,從而提高性能。

加鎖過程

在代碼進(jìn)入同步塊的時候,如果同步對象鎖狀態(tài)為無鎖狀態(tài)(鎖標(biāo)志位為 01 狀態(tài),是否為偏向鎖為 0 ),虛擬機(jī)首先將在當(dāng)前線程的棧幀中建立一個名為鎖記錄(Lock Record)的空間,用于存儲鎖對象目前的 Mark Word 的拷貝,然后拷貝對象頭中的 Mark Word 復(fù)制到鎖記錄中。

 

詳解Java鎖機(jī)制:看完你就明白的鎖系列之鎖的狀態(tài)

 

拷貝成功后,虛擬機(jī)將使用 CAS 操作嘗試將對象的 Mark Word 更新為指向 Lock Record 的指針,并將 Lock Record里的 owner 指針指向?qū)ο蟮?Mark Word。

如果這個更新動作成功了,那么這個線程就擁有了該對象的鎖,并且對象Mark Word的鎖標(biāo)志位設(shè)置為 00 ,表示此對象處于輕量級鎖定狀態(tài)。

 

詳解Java鎖機(jī)制:看完你就明白的鎖系列之鎖的狀態(tài)

 

如果這個更新操作失敗了,虛擬機(jī)首先會檢查對象的 Mark Word 是否指向當(dāng)前線程的棧幀,如果是就說明當(dāng)前線程已經(jīng)擁有了這個對象的鎖,那就可以直接進(jìn)入同步塊繼續(xù)執(zhí)行。否則說明多個線程競爭鎖,輕量級鎖就要膨脹為重量級鎖,鎖標(biāo)志的狀態(tài)值變?yōu)? 10 ,Mark Word中存儲的就是指向重量級鎖(互斥量)的指針,后面等待鎖的線程也要進(jìn)入阻塞狀態(tài)。

重量級鎖

重量級鎖也就是通常說 synchronized 的對象鎖,鎖標(biāo)識位為10,其中指針指向的是 monitor 對象(也稱為管程或監(jiān)視器鎖)的起始地址。每個對象都存在著一個 monitor 與之關(guān)聯(lián),對象與其 monitor 之間的關(guān)系有存在多種實(shí)現(xiàn)方式,如 monitor 可以與對象一起創(chuàng)建銷毀或當(dāng)線程試圖獲取對象鎖時自動生成,但當(dāng)一個 monitor 被某個線程持有后,它便處于鎖定狀態(tài)。

 

詳解Java鎖機(jī)制:看完你就明白的鎖系列之鎖的狀態(tài)

 

上圖簡單描述多線程獲取鎖的過程,當(dāng)多個線程同時訪問一段同步代碼時,首先會進(jìn)入 Entry Set當(dāng)線程獲取到對象的 monitor 后進(jìn)入 The Owner 區(qū)域并把 monitor 中的 owner 變量設(shè)置為當(dāng)前線程,同時 monitor 中的計(jì)數(shù)器count 加1,若線程調(diào)用 wait() 方法,將釋放當(dāng)前持有的 monitor,owner變量恢復(fù)為 null,count自減1,同時該線程進(jìn)入 WaitSet 集合中等待被喚醒。若當(dāng)前線程執(zhí)行完畢也將釋放 monitor (鎖)并復(fù)位變量的值,以便其他線程進(jìn)入獲取monitor(鎖)。

由此看來,monitor 對象存在于每個Java對象的對象頭中(存儲的指針的指向),synchronized 鎖便是通過這種方式獲取鎖的,也是為什么Java中任意對象可以作為鎖的原因,同時也是 notify/notifyAll/wait 等方法存在于頂級對象Object中的原因。

責(zé)任編輯:武曉燕 來源: 今日頭條
相關(guān)推薦

2020-04-24 15:44:50

MySQL數(shù)據(jù)庫鎖機(jī)制

2023-06-09 07:59:37

多線程編程鎖機(jī)制

2023-12-01 08:39:29

分布式鎖系統(tǒng)

2019-01-04 11:18:35

獨(dú)享鎖共享鎖非公平鎖

2024-03-18 12:21:28

Java輕量級鎖重量級鎖

2019-12-19 17:00:01

Java線程

2019-12-25 10:45:30

Java悲觀鎖

2024-01-29 01:08:01

悲觀鎖遞歸鎖讀寫鎖

2020-09-16 07:56:28

多線程讀寫鎖悲觀鎖

2024-01-29 07:43:42

Java獨(dú)占鎖共享鎖

2021-03-31 10:05:26

偏向鎖輕量級鎖

2019-11-28 16:00:06

重入鎖讀寫鎖樂觀鎖

2025-06-13 10:00:00

JavaJUC 包

2024-09-29 08:39:51

2020-07-06 08:03:32

Java悲觀鎖樂觀鎖

2018-07-31 10:10:06

MySQLInnoDB死鎖

2025-06-04 02:55:00

MySQL意向鎖記錄鎖

2020-08-26 08:59:58

Linux線程互斥鎖

2021-08-03 07:40:46

Synchronize鎖膨脹性能

2024-05-11 09:03:26

數(shù)據(jù)表級鎖事務(wù)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 久久精品国产免费看久久精品 | 国产成人精品a视频一区www | 91在线电影 | 久久精品av | 九九色综合| 欧美黄 片免费观看 | 国产a视频 | 超碰人人在线 | 亚洲男人的天堂网站 | 亚洲精品日本 | 成人欧美一区二区三区黑人孕妇 | 国产精品久久久久久久久免费丝袜 | 一区二区三区免费观看 | 日韩一区在线播放 | 精品国产久 | 久久躁日日躁aaaaxxxx | 精品美女久久久 | 国产精品久久久久久久久久久久久久 | 不卡在线一区 | 日本一区二区高清不卡 | 欧美不卡一区二区三区 | 日韩中文字幕一区二区 | 日本一区二区在线视频 | 中文字幕成人av | 99久久久国产精品 | 欧美13videosex性极品 | 欧美日韩国产中文字幕 | 国产一区二区精品自拍 | 午夜国产一区 | 91精品国产91久久久久久密臀 | 全免费a级毛片免费看视频免费下 | 黄色永久免费 | 免费九九视频 | 伊人久久在线 | 午夜精品久久久久久久久久久久久 | 国产精品免费一区二区三区四区 | 视频一区二区三区中文字幕 | 亚洲精品视频三区 | 综合久久av| 一区二区三区国产好 | 久久99精品久久久久久 |