日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

synchronize原理

發(fā)布時(shí)間:2023/12/13 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 synchronize原理 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

?

synchronized的三種應(yīng)用方式

一. 修飾實(shí)例方法,作用于當(dāng)前實(shí)例加鎖,進(jìn)入同步代碼前要獲得當(dāng)前實(shí)例的鎖。

二. 修飾靜態(tài)方法,作用于當(dāng)前類對(duì)象加鎖,進(jìn)入同步代碼前要獲得當(dāng)前類對(duì)象的鎖。

三. 修飾代碼塊,指定加鎖對(duì)象,對(duì)給定對(duì)象加鎖,進(jìn)入同步代碼庫(kù)前要獲得給定對(duì)象。

synchronized的字節(jié)碼指令

  synchronized同步塊使用了monitorenter和monitorexit指令實(shí)現(xiàn)同步,這兩個(gè)指令,本質(zhì)上都是對(duì)一個(gè)對(duì)象的監(jiān)視器(monitor)進(jìn)行獲取,這個(gè)過(guò)程是排他的,也就是說(shuō)同一時(shí)刻只能有一個(gè)線程獲取到由synchronized所保護(hù)對(duì)象的監(jiān)視器。

  線程執(zhí)行到monitorenter指令時(shí),會(huì)嘗試獲取對(duì)象所對(duì)應(yīng)的monitor所有權(quán),也就是嘗試獲取對(duì)象的鎖,而執(zhí)行monitorexit,就是釋放monitor的所有權(quán)。

synchronized的鎖的原理

  兩個(gè)重要的概念:一個(gè)是對(duì)象頭,另一個(gè)是monitor。

Java對(duì)象頭

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

Mark Word

  Mark Word用于存儲(chǔ)對(duì)象自身的運(yùn)行時(shí)數(shù)據(jù),如哈希碼(HashCode)、GC分代年齡、鎖狀態(tài)標(biāo)志、線程持有的
鎖、偏向線程 ID、偏向時(shí)間戳等等。Java對(duì)象頭一般占有兩個(gè)機(jī)器碼(在32位虛擬機(jī)中,1個(gè)機(jī)器碼等于4字節(jié),
也就是32bit)。

?

?

Class Metadata Address

  類型指針,即是對(duì)象指向它的類的元數(shù)據(jù)的指針,虛擬機(jī)通過(guò)這個(gè)指針來(lái)確定這個(gè)對(duì)象是哪個(gè)類的實(shí)例。

Array length

如果對(duì)象是一個(gè)Java數(shù)組,那在對(duì)象頭中還必須有一塊用于記錄數(shù)組長(zhǎng)度的數(shù)據(jù)。

Monitor

  Monitor是一個(gè)同步工具,它內(nèi)置于每一個(gè)Object對(duì)象中,相當(dāng)于一個(gè)許可證。拿到許可證即可以進(jìn)行操作,沒(méi)有拿到則需要阻塞等待。

  在hotspot虛擬機(jī)中,通過(guò)ObjectMonitor類來(lái)實(shí)現(xiàn)monitor。

?

?

synchronized鎖的優(yōu)化

  jdk1.6以后對(duì)synchronized的鎖進(jìn)行了優(yōu)化,引入了偏向鎖、輕量級(jí)鎖,鎖的級(jí)別從低到高逐步升級(jí):?

  無(wú)鎖->偏向鎖->輕量級(jí)鎖->重量級(jí)鎖

自旋鎖與自適應(yīng)自旋

  線程的掛起和恢復(fù)會(huì)極大的影響開(kāi)銷。并且jdk官方人員發(fā)現(xiàn),很多線程在等待鎖的時(shí)候,在很短的一段時(shí)間就獲得了鎖,所以它們?cè)诰€程等待的時(shí)候,并不需要把線程掛起,而是讓他無(wú)目的的循環(huán),一般設(shè)置10次。這樣就避免了線程切換的開(kāi)銷,極大的提升了性能。

而適應(yīng)性自旋,是賦予了自旋一種學(xué)習(xí)能力,它并不固定自旋10次一下。他可以根據(jù)它前面線程的自旋情況,從而調(diào)整它的自旋,甚至是不經(jīng)過(guò)自旋而直接掛起。

鎖消除

  對(duì)不會(huì)存在線程安全的鎖進(jìn)行消除。

鎖粗化

  如果jvm檢測(cè)到有一串零碎的操作都對(duì)同一個(gè)對(duì)象加鎖,將會(huì)把鎖粗化到整個(gè)操作外部,如循環(huán)體。

偏向鎖

  多數(shù)情況下,鎖不僅不存在多線程競(jìng)爭(zhēng),而且總是由同一線程多次獲得,為了讓其獲得鎖的代價(jià)更低而引入了偏向鎖。

  當(dāng)一個(gè)線程訪問(wèn)同步塊并獲取鎖時(shí),會(huì)在對(duì)象頭和棧幀中的鎖記錄里存儲(chǔ)鎖偏向的線程ID,以后該線程在進(jìn)入和退出同步塊時(shí)不需要進(jìn)行CAS操作來(lái)加鎖和解鎖,只需簡(jiǎn)單地測(cè)試一下對(duì)象頭的Mark Word里是否存儲(chǔ)著指向當(dāng)前線程的偏向鎖。

  如果測(cè)試成功,表示線程已經(jīng)獲得了鎖。

  如果測(cè)試失敗,則需要再測(cè)試一下Mark Word中偏向鎖的標(biāo)識(shí)是否設(shè)置成01(表示當(dāng)前是偏向鎖)。

  如果沒(méi)有設(shè)置,則使用CAS競(jìng)爭(zhēng)鎖。

  如果設(shè)置了,則嘗試使用CAS將對(duì)象頭的偏向鎖指向當(dāng)前線程。

輕量級(jí)鎖

  引入輕量級(jí)鎖的主要目的是在多線程競(jìng)爭(zhēng)不激烈的情況下,通過(guò)CAS競(jìng)爭(zhēng)鎖,減少傳統(tǒng)的重量級(jí)鎖使用操作系統(tǒng)互斥量產(chǎn)生的性能消耗。

重量級(jí)鎖

  重量級(jí)鎖通過(guò)對(duì)象內(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)的切換,切換成本非常高。

鎖升級(jí)

  偏向鎖升級(jí)輕量級(jí)鎖:當(dāng)一個(gè)對(duì)象持有偏向鎖,一旦第二個(gè)線程訪問(wèn)這個(gè)對(duì)象,如果產(chǎn)生競(jìng)爭(zhēng),偏向鎖升級(jí)為輕量級(jí)鎖。

  輕量級(jí)鎖升級(jí)重量級(jí)鎖:一般兩個(gè)線程對(duì)于同一個(gè)鎖的操作都會(huì)錯(cuò)開(kāi),或者說(shuō)稍微等待一下(自旋),另一個(gè)線程就會(huì)釋放鎖。但是當(dāng)自旋超過(guò)一定的次數(shù),或者一個(gè)線程在持有鎖,一個(gè)在自旋,又有第三個(gè)來(lái)訪時(shí),輕量級(jí)鎖膨脹為重量級(jí)鎖,重量級(jí)鎖使除了擁有鎖的線程以外的線程都阻塞,防止CPU空轉(zhuǎn)。

wait和notify的原理

  調(diào)用wait方法,首先會(huì)獲取監(jiān)視器鎖,獲得成功以后,會(huì)讓當(dāng)前線程進(jìn)入等待狀態(tài)進(jìn)入等待隊(duì)列并且釋放鎖。

  當(dāng)其他線程調(diào)用notify后,會(huì)選擇從等待隊(duì)列中喚醒任意一個(gè)線程,而執(zhí)行完notify方法以后,并不會(huì)立馬喚醒線程,原因是當(dāng)前的線程仍然持有這把鎖,處于等待狀態(tài)的線程無(wú)法獲得鎖。必須要等到當(dāng)前的線程執(zhí)行完按monitorexit指令以后,也就是鎖被釋放以后,處于等待隊(duì)列中的線程就可以開(kāi)始競(jìng)爭(zhēng)鎖了。

wait和notify為什么需要在synchronized里面?

  wait方法的語(yǔ)義有兩個(gè),一個(gè)是釋放當(dāng)前的對(duì)象鎖、另一個(gè)是使得當(dāng)前線程進(jìn)入阻塞隊(duì)列,而這些操作都和監(jiān)視器是相關(guān)的,所以wait必須要獲得一個(gè)監(jiān)視器鎖。

而對(duì)于notify來(lái)說(shuō)也是一樣,它是喚醒一個(gè)線程,既然要去喚醒,首先得知道它在哪里,所以就必須要找到這個(gè)對(duì)象獲取到這個(gè)對(duì)象的鎖,然后到這個(gè)對(duì)象的等待隊(duì)列中去喚醒一個(gè)線程。

轉(zhuǎn)載于:https://www.cnblogs.com/heqiyoujing/p/11144649.html

總結(jié)

以上是生活随笔為你收集整理的synchronize原理的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。