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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

synchronize原理

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

?

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

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

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

三. 修飾代碼塊,指定加鎖對象,對給定對象加鎖,進入同步代碼庫前要獲得給定對象。

synchronized的字節(jié)碼指令

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

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

synchronized的鎖的原理

  兩個重要的概念:一個是對象頭,另一個是monitor。

Java對象頭

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

Mark Word

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

?

?

Class Metadata Address

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

Array length

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

Monitor

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

  在hotspot虛擬機中,通過ObjectMonitor類來實現(xiàn)monitor。

?

?

synchronized鎖的優(yōu)化

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

  無鎖->偏向鎖->輕量級鎖->重量級鎖

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

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

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

鎖消除

  對不會存在線程安全的鎖進行消除。

鎖粗化

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

偏向鎖

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

  當(dāng)一個線程訪問同步塊并獲取鎖時,會在對象頭和棧幀中的鎖記錄里存儲鎖偏向的線程ID,以后該線程在進入和退出同步塊時不需要進行CAS操作來加鎖和解鎖,只需簡單地測試一下對象頭的Mark Word里是否存儲著指向當(dāng)前線程的偏向鎖。

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

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

  如果沒有設(shè)置,則使用CAS競爭鎖。

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

輕量級鎖

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

重量級鎖

  重量級鎖通過對象內(nèi)部的監(jiān)視器(monitor)實現(xiàn),其中monitor的本質(zhì)是依賴于底層操作系統(tǒng)的Mutex Lock實現(xiàn),操作系統(tǒng)實現(xiàn)線程之間的切換需要從用戶態(tài)到內(nèi)核態(tài)的切換,切換成本非常高。

鎖升級

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

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

wait和notify的原理

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

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

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

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

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

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

總結(jié)

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

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