最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊

synchronized的實(shí)現(xiàn)原理

2022-01-09 23:43 作者:迪巴哥沒八哥  | 我要投稿

synchronized的實(shí)現(xiàn)原理

大家好我是debug沒有bug的迪吧哥,今天不加班,和大家來扯一扯synchronized。

Synchronized通常稱為重量級鎖,但是Java SE1.6后對synchronized進(jìn)行了各種優(yōu)化。Java中每個(gè)對象都可作為鎖,具體有如下3種形式:

  1. 對于普通方法,鎖是當(dāng)前實(shí)例對象。


    現(xiàn)象:先逐行輸出mythread1,線程1:RUNNABLE,線程2:BLOCKED,之后暫停五分鐘,逐行輸出sleep end,mythread2

    分析:線程2與線程1擁有相同的鎖,線程1優(yōu)先級高于線程2,線程1優(yōu)先執(zhí)行,獲取到鎖,執(zhí)行sleep,未釋放鎖,線程2未獲取到鎖,處于阻塞狀態(tài),線程1sleep結(jié)束,輸出sleep end,并釋放鎖,線程2獲取到鎖,執(zhí)行輸出mythread2

    結(jié)論:當(dāng)synchronized修飾普通方法時(shí),鎖對象即為當(dāng)前對象

  2. 對于靜態(tài)同步方法,鎖的是當(dāng)前類的class對象。

    對上述代碼稍作修改,在dosome方法上添加static關(guān)鍵字,main方法中,線程2對象初始化時(shí),傳入MyThread1.class


    現(xiàn)象:與上述現(xiàn)象一致

    分析:同上

    結(jié)論:當(dāng)synchronized修飾靜態(tài)方法時(shí),鎖對象為當(dāng)前Class對象

  3. 對于同步方法快,鎖的是synchonized括號(hào)內(nèi)的配置對象。


當(dāng)一個(gè)線程試圖訪問同步代碼塊時(shí),首先必須得到鎖,退出或拋出異常必須釋放鎖。鎖存在哪里? 鎖有哪些信息?

JVM規(guī)范可看到Synchonized在JVM里的實(shí)現(xiàn)原理,JVM基于進(jìn)入與退出Monitor對象實(shí)現(xiàn)方法同步與代碼塊同步。代碼塊同步使用monitorenter和monitorexit指令實(shí)現(xiàn)的,方法同步用另外方式實(shí)現(xiàn),細(xì)節(jié)再JVM規(guī)范沒詳細(xì)說明。方法同步用這兩個(gè)指令實(shí)現(xiàn)。

monitorenter指令在編譯后插入到同步代碼塊開始位置,而monitorexit插入到方法結(jié)束與異常處,JVM保證每個(gè)monitorenter必須有相應(yīng)monitorexit與之配對。任何對象有一個(gè)monitor與之關(guān)聯(lián),當(dāng)一個(gè)monitor被持有后,它處于鎖定狀態(tài)。

我們執(zhí)行以下代碼,并且結(jié)合hsdis-amd64.dl工具查看控制臺(tái)的字節(jié)碼指令:


字節(jié)碼指令:


我們可以看到 有ACC_SYNCHRONIZED, 它使用了monitorenter與monitorexit指令,隱式執(zhí)行了Lock與Unlock操作,提供原子性。

synchronized鎖的原理

jdk1.6后對Synchonized鎖優(yōu)化,有偏向鎖、輕量級鎖、重量級鎖。

我們通過一下三個(gè)問題來了解synchronized原理:

  1. synchronized如何實(shí)現(xiàn)鎖

  2. 為什么任何一個(gè)對象都可以成為鎖

  3. 鎖存在哪個(gè)地方?

了解synchronized前,我們需了解兩個(gè)重要概念,一個(gè)是對象頭,一個(gè)是monitor。

Java對象頭:

在Hotspot虛擬機(jī)中,對象在內(nèi)存的布局分為三塊區(qū)域:對象頭、實(shí)例數(shù)據(jù)與對象填充;Java對象頭是實(shí)現(xiàn)synchronized鎖對象基礎(chǔ),synchronized使用鎖對象存儲(chǔ)在Java對象頭里。是輕量級鎖與偏向鎖關(guān)鍵。

Mawrk Word:

Mark word用于存儲(chǔ)對象自身運(yùn)行時(shí)數(shù)據(jù),如哈希瑪、GC分代年齡、鎖狀態(tài)標(biāo)志、線程持有鎖、偏向線程ID\偏向時(shí)間戳等。Java對象頭一般占有兩機(jī)器碼,如下所示:


Monitor:

Monitor是什么? 可理解為一個(gè)同步工具,也是一種同步機(jī)制。Java對象是天生的Monitor,每個(gè)object對象里markOop->monitor()里可保存ObjectMonitor對象。

Synchronized如何實(shí)現(xiàn)鎖?

了解了對象頭和monitor之后我們可以分析synchronized鎖的實(shí)現(xiàn)。

樂觀鎖:

樂觀鎖認(rèn)為讀多寫少,每次拿數(shù)據(jù)的時(shí)候認(rèn)為別人不修改,不會(huì)上鎖,更新的時(shí)候判斷這個(gè)期間又沒人更新數(shù)據(jù),寫的時(shí)候先讀出版本號(hào),然后加鎖操作,如果失敗,重復(fù)操作。java中樂觀鎖基本通過CAS實(shí)現(xiàn),比較當(dāng)前值和傳入值是否一樣。

悲觀鎖:

悲觀就是認(rèn)為寫多讀少,拿數(shù)據(jù)時(shí)都認(rèn)為別人會(huì)修改,所以每次讀寫會(huì)上鎖,所以別人讀寫數(shù)據(jù)會(huì)block直到拿到鎖。java中悲觀鎖是Synchronized,AQS框架的鎖先嘗試cas樂觀鎖獲取鎖,獲取不到轉(zhuǎn)化為悲觀鎖,如RetreenLock,還有數(shù)據(jù)庫一般本身鎖的機(jī)制也是基于悲觀鎖的機(jī)制實(shí)現(xiàn)的。

自旋鎖(CAS):

自旋鎖讓不滿足條件的線程等待一段時(shí)間,自旋就是一段循環(huán),通過占用處理器時(shí)間避免線程切換帶來的開銷,但是如果持有鎖定線程不能很快釋放鎖會(huì)浪費(fèi)資源,下面是自旋鎖代碼演示。


偏向鎖:

很多情況,鎖沒有存在多線程競爭,而是由同一線程多次獲得,為了讓線程獲取鎖代價(jià)變低引入偏向鎖。下圖是偏向鎖獲得與撤銷圖。


1、線程訪問同步塊獲取鎖,對想頭與棧幀鎖記錄存儲(chǔ)鎖偏向的線程ID。

2、線程進(jìn)入退出同步快不要cas操作,只需簡單測試Mark Word是否存儲(chǔ)線程偏向鎖。

3、測試成功,表示線程獲得鎖,測試失敗,測試Mark Word偏向鎖標(biāo)識(shí)是否為01,沒有設(shè)置則使用CAS競爭鎖,設(shè)置了。嘗試用CAS把對象頭偏向鎖指向當(dāng)前線程。

4、執(zhí)行同步塊,線程2訪問同步塊,檢查對象頭Mark Word是否存儲(chǔ)線程2的偏向鎖,不是側(cè)進(jìn)入cas替換,此時(shí)替換失敗,線程1已經(jīng)替換。

輕量級鎖:

引入輕量級鎖的主要目的是在多沒有多線程競爭的前提下,減少傳統(tǒng)的重量級鎖使用操作系統(tǒng)互斥量產(chǎn)生的性能消耗。當(dāng)關(guān)閉偏向鎖功能或者多個(gè)線程競爭偏向鎖導(dǎo)致偏向鎖升級為輕量級鎖,則會(huì)嘗試獲取輕量級鎖,下面是輕量級鎖的流程圖:


重量級鎖:

重量級鎖通過對象內(nèi)部的監(jiān)視器(monitor)實(shí)現(xiàn),其中monitor的本質(zhì)是依賴于底層操作系統(tǒng)的Mutex Lock實(shí)現(xiàn),操作系統(tǒng)實(shí)現(xiàn)線程之間的切換需要從用戶態(tài)到內(nèi)核態(tài)的切換,切換成本非常高。主要是,當(dāng)系統(tǒng)檢查到鎖是重量級鎖之后,會(huì)把等待想要獲得鎖的線程進(jìn)行阻塞,被阻塞的線程不會(huì)消耗cup。但是阻塞或者喚醒一個(gè)線程時(shí),都需要操作系統(tǒng)來幫忙,這就需要從用戶態(tài)轉(zhuǎn)換到內(nèi)核態(tài),而轉(zhuǎn)換狀態(tài)是需要消耗很多時(shí)間的,有可能比用戶執(zhí)行代碼的時(shí)間還要長。這就是說為什么重量級線程開銷很大的。


好了,今天的分享就到這里了,我是debug沒bug的迪吧哥,你的點(diǎn)贊關(guān)注是對我的最大支持,感謝你的分享。

公眾號(hào)、b站、知乎、csdn:迪巴哥沒八哥

synchronized的實(shí)現(xiàn)原理的評論 (共 條)

分享到微博請遵守國家法律
剑川县| 津市市| 红安县| 茌平县| 西华县| 彰化县| 从化市| 连江县| 鹤峰县| 永定县| 蓬安县| 桃园市| 新沂市| 容城县| 汉阴县| 平顶山市| 吴桥县| 淮滨县| 沙洋县| 伊金霍洛旗| 满洲里市| 岳普湖县| 二手房| 马山县| 宜都市| 阳春市| 五华县| 任丘市| 长泰县| 汉川市| 蓬莱市| 饶河县| 红桥区| 濮阳市| 镇江市| 鹤峰县| 五华县| 珲春市| 蕉岭县| 逊克县| 喀喇沁旗|