Java基礎(chǔ)-線程-synchronized

synchronized實現(xiàn)原理

在java代碼中使用synchronized可是使用在代碼塊和方法中锰茉,根據(jù)Synchronized用的位置可以有這些使用場景:


image.png

如果鎖的是類的話呢蔫,盡管new多個實例對象,但他們?nèi)匀皇菍儆谕粋€類依然會被鎖住,即線程之間保證同步關(guān)系片吊。

對象鎖(monitor)機制

  • 鎖住的是類
    用javap -v SynchronizedDemo.class查看字節(jié)碼文件:


    image.png
  • 上面用黃色高亮的部分就是需要注意的部分了绽昏,這也是添Synchronized關(guān)鍵字之后獨有的。執(zhí)行同步代碼塊后首先要先執(zhí)行monitorenter指令俏脊,退出的時候monitorexit指令
  • 使用Synchronized進(jìn)行同步全谤,其關(guān)鍵就是必須要對對象的監(jiān)視器monitor進(jìn)行獲取,當(dāng)線程獲取monitor后才能繼續(xù)往下執(zhí)行爷贫,否則就只能等待认然。而這個獲取的過程是互斥的,即同一時刻只有一個線程能夠獲取到monitor
  • 執(zhí)行靜態(tài)同步方法的時候就只有一條monitorexit指令漫萄,并沒有monitorenter獲取鎖的指令卷员。這就是鎖的重入性,即在同一鎖程中腾务,線程不需要再次獲取同一把鎖毕骡。Synchronized先天具有重入性。每個對象擁有一個計數(shù)器岩瘦,當(dāng)線程獲取該對象鎖后未巫,計數(shù)器就會加一,釋放鎖后就會將計數(shù)器減一启昧。
  • 任意一個對象都擁有自己的監(jiān)視器叙凡,當(dāng)這個對象由同步塊或者這個對象的同步方法調(diào)用時,執(zhí)行方法的線程必須先獲取該對象的監(jiān)視器才能進(jìn)入同步塊和同步方法箫津,如果沒有獲取到監(jiān)視器的線程將會被阻塞在同步塊和同步方法的入口處狭姨,進(jìn)入到BLOCKED狀態(tài)

synchronized的happens-before關(guān)系

對同一個監(jiān)視器的解鎖宰啦,happens-before于對該監(jiān)視器的加鎖苏遥。繼續(xù)來看代碼:

public class MonitorDemo {
    private int a = 0;

    public synchronized void writer() {     // 1
        a++;                                // 2
    }                                       // 3

    public synchronized void reader() {    // 4
        int i = a;                         // 5
    }                                      // 6
}

根據(jù)happens-before的定義中的一條:如果A happens-before B,則A的執(zhí)行結(jié)果對B可見赡模,并且A的執(zhí)行順序先于B田炭。線程A先對共享變量A進(jìn)行加一,由2 happens-before 5關(guān)系可知線程A的執(zhí)行結(jié)果對線程B可見即線程B所讀取到的a的值為1漓柑。

第四步獲得鎖之后教硫,writer方法里所有的各種變量的處理,對于reader方法辆布,都是可見的瞬矩。

鎖獲取和鎖釋放的內(nèi)存語義

image.png

從整體上來看,線程A的執(zhí)行結(jié)果(a=1)對線程B是可見的锋玲,實現(xiàn)原理為:釋放鎖的時候會將值刷新到主內(nèi)存中景用,其他線程獲取鎖時會強制從主內(nèi)存中獲取最新的值。另外也驗證了2 happens-before 5惭蹂,2的執(zhí)行結(jié)果對5是可見的伞插。

從橫向來看割粮,這就像線程A通過主內(nèi)存中的共享變量和線程B進(jìn)行通信,A 告訴 B 我們倆的共享數(shù)據(jù)現(xiàn)在為1啦媚污,這種線程間的通信機制正好吻合java的內(nèi)存模型正好是共享內(nèi)存的并發(fā)模型結(jié)構(gòu)舀瓢。

synchronized優(yōu)化

CAS的應(yīng)用場景

  • 在J.U.C包中利用CAS實現(xiàn)類有很多,可以說是支撐起整個concurrency包的實現(xiàn)耗美,在Lock實現(xiàn)中會有CAS改變state變量京髓,在atomic包中的實現(xiàn)類也幾乎都是用CAS實現(xiàn),關(guān)于這些具體的實現(xiàn)場景在之后會詳細(xì)聊聊幽歼,現(xiàn)在有個印象就好了
  • CAS的問題
    1. ABA問題
      因為CAS會檢查舊值有沒有變化朵锣,這里存在這樣一個有意思的問題。比如一個舊值A(chǔ)變?yōu)榱顺葿甸私,然后再變成A诚些,剛好在做CAS時檢查發(fā)現(xiàn)舊值并沒有變化依然為A,但是實際上的確發(fā)生了變化皇型。解決方案可以沿襲數(shù)據(jù)庫中常用的樂觀鎖方式诬烹,添加一個版本號可以解決。原來的變化路徑A->B->A就變成了1A->2B->3C弃鸦。java這么優(yōu)秀的語言绞吁,當(dāng)然在java 1.5后的atomic包中提供了AtomicStampedReference來解決ABA問題,解決思路就是這樣的唬格。
    1. 自旋時間過長
      使用CAS時非阻塞同步家破,也就是說不會將線程掛起,會自旋(無非就是一個死循環(huán))進(jìn)行下一次嘗試购岗,如果這里自旋時間過長對性能是很大的消耗汰聋。如果JVM能支持處理器提供的pause指令,那么在效率上會有一定的提升喊积。
    1. 只能保證一個共享變量的原子操作
      當(dāng)對一個共享變量執(zhí)行操作時CAS能保證其原子性烹困,如果對多個共享變量進(jìn)行操作,CAS就不能保證其原子性。有一個解決方案是利用對象整合多個共享變量乾吻,即一個類中的成員變量就是這幾個共享變量髓梅。然后將這個對象做CAS操作就可以保證其原子性。atomic中提供了AtomicReference來保證引用對象之間的原子性绎签。

Java對象頭

在同步的時候是獲取對象的monitor,即獲取到對象的鎖枯饿。那么對象的鎖怎么理解?無非就是類似對對象的一個標(biāo)志诡必,那么這個標(biāo)志就是存放在Java對象的對象頭奢方。Java對象頭里的Mark Word里默認(rèn)的存放的對象的Hashcode,分代年齡和鎖標(biāo)記位。32為JVM Mark Word默認(rèn)存儲結(jié)構(gòu)為


image.png

Java SE 1.6中,鎖一共有4種狀態(tài)袱巨,級別從低到高依次是:無鎖狀態(tài)阁谆、偏向鎖狀態(tài)、輕量級鎖狀態(tài)和重量級鎖狀態(tài)愉老,這幾個狀態(tài)會隨著競爭情況逐漸升級场绿。鎖可以升級但不能降級,意味著偏向鎖升級成輕量級鎖后不能降級成偏向鎖嫉入。這種鎖升級卻不能降級的策略焰盗,目的是為了提高獲得鎖和釋放鎖的效率


image.png
  • 偏向鎖
    HotSpot的作者經(jīng)過研究發(fā)現(xiàn),大多數(shù)情況下咒林,鎖不僅不存在多線程競爭熬拒,而且總是由同一線程多次獲得,為了讓線程獲得鎖的代價更低而引入了偏向鎖垫竞。

  • 當(dāng)一個線程訪問同步塊并獲取鎖時澎粟,會在對象頭和棧幀中的鎖記錄里存儲鎖偏向的線程ID,以后該線程在進(jìn)入和退出同步塊時不需要進(jìn)行CAS操作來加鎖和解鎖欢瞪,只需簡單地測試一下對象頭的Mark Word里是否存儲著指向當(dāng)前線程的偏向鎖活烙。如果測試成功,表示線程已經(jīng)獲得了鎖遣鼓。如果測試失敗啸盏,則需要再測試一下Mark Word中偏向鎖的標(biāo)識是否設(shè)置成1(表示當(dāng)前是偏向鎖):如果沒有設(shè)置,則使用CAS競爭鎖骑祟;如果設(shè)置了回懦,則嘗試使用CAS將對象頭的偏向鎖指向當(dāng)前線程

  • 偏向鎖使用了一種等到競爭出現(xiàn)才釋放鎖的機制,所以當(dāng)其他線程嘗試競爭偏向鎖時次企,持有偏向鎖的線程才會釋放鎖怯晕。

  • 偏向鎖的撤銷,需要等待全局安全點(在這個時間點上沒有正在執(zhí)行的字節(jié)碼)抒巢。它會首先暫停擁有偏向鎖的線程贫贝,然后檢查持有偏向鎖的線程是否活著秉犹,如果線程不處于活動狀態(tài)蛉谜,則將對象頭設(shè)置成無鎖狀態(tài);如果線程仍然活著崇堵,擁有偏向鎖的棧會被執(zhí)行型诚,遍歷偏向?qū)ο蟮逆i記錄,棧中的鎖記錄和對象頭的Mark Word要么重新偏向于其他線程鸳劳,要么恢復(fù)到無鎖或者標(biāo)記對象不適合作為偏向鎖狰贯,最后喚醒暫停的線程。

  • 偏向鎖在Java 6和Java 7里是默認(rèn)啟用的,但是它在應(yīng)用程序啟動幾秒鐘之后才激活涵紊,如有必要可以使用JVM參數(shù)來關(guān)閉延遲:-XX:BiasedLockingStartupDelay=0傍妒。如果你確定應(yīng)用程序里所有的鎖通常情況下處于競爭狀態(tài),可以通過JVM參數(shù)關(guān)閉偏向鎖:-XX:-UseBiasedLocking=false摸柄,那么程序默認(rèn)會進(jìn)入輕量級鎖狀態(tài)

  • 輕量級鎖

  • 線程在執(zhí)行同步塊之前颤练,JVM會先在當(dāng)前線程的棧楨中創(chuàng)建用于存儲鎖記錄的空間,并將對象頭中的Mark Word復(fù)制到鎖記錄中驱负,官方稱為Displaced Mark Word嗦玖。然后線程嘗試使用CAS將對象頭中的Mark Word替換為指向鎖記錄的指針。如果成功跃脊,當(dāng)前線程獲得鎖宇挫,如果失敗,表示其他線程競爭鎖酪术,當(dāng)前線程便嘗試使用自旋來獲取鎖器瘪。

  • 輕量級解鎖時,會使用原子的CAS操作將Displaced Mark Word替換回到對象頭绘雁,如果成功娱局,則表示沒有競爭發(fā)生。如果失敗咧七,表示當(dāng)前鎖存在競爭衰齐,鎖就會膨脹成重量級鎖。

  • 各種鎖的比較


    image.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末继阻,一起剝皮案震驚了整個濱河市耻涛,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌瘟檩,老刑警劉巖抹缕,帶你破解...
    沈念sama閱讀 219,366評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異墨辛,居然都是意外死亡卓研,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評論 3 395
  • 文/潘曉璐 我一進(jìn)店門睹簇,熙熙樓的掌柜王于貴愁眉苦臉地迎上來奏赘,“玉大人,你說我怎么就攤上這事太惠∧ヌ剩” “怎么了?”我有些...
    開封第一講書人閱讀 165,689評論 0 356
  • 文/不壞的土叔 我叫張陵凿渊,是天一觀的道長梁只。 經(jīng)常有香客問我缚柳,道長,這世上最難降的妖魔是什么搪锣? 我笑而不...
    開封第一講書人閱讀 58,925評論 1 295
  • 正文 為了忘掉前任秋忙,我火速辦了婚禮,結(jié)果婚禮上构舟,老公的妹妹穿的比我還像新娘翰绊。我一直安慰自己,他們只是感情好旁壮,可當(dāng)我...
    茶點故事閱讀 67,942評論 6 392
  • 文/花漫 我一把揭開白布监嗜。 她就那樣靜靜地躺著,像睡著了一般抡谐。 火紅的嫁衣襯著肌膚如雪裁奇。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,727評論 1 305
  • 那天麦撵,我揣著相機與錄音刽肠,去河邊找鬼。 笑死免胃,一個胖子當(dāng)著我的面吹牛音五,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播羔沙,決...
    沈念sama閱讀 40,447評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼躺涝,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了扼雏?” 一聲冷哼從身側(cè)響起坚嗜,我...
    開封第一講書人閱讀 39,349評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎诗充,沒想到半個月后苍蔬,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,820評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡蝴蜓,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,990評論 3 337
  • 正文 我和宋清朗相戀三年碟绑,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片茎匠。...
    茶點故事閱讀 40,127評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡格仲,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出汽抚,到底是詐尸還是另有隱情抓狭,我是刑警寧澤伯病,帶...
    沈念sama閱讀 35,812評論 5 346
  • 正文 年R本政府宣布造烁,位于F島的核電站否过,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏惭蟋。R本人自食惡果不足惜苗桂,卻給世界環(huán)境...
    茶點故事閱讀 41,471評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望告组。 院中可真熱鬧煤伟,春花似錦、人聲如沸木缝。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,017評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽我碟。三九已至放案,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間矫俺,已是汗流浹背吱殉。 一陣腳步聲響...
    開封第一講書人閱讀 33,142評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留厘托,地道東北人友雳。 一個月前我還...
    沈念sama閱讀 48,388評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像铅匹,于是被迫代替她去往敵國和親押赊。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,066評論 2 355

推薦閱讀更多精彩內(nèi)容