多線程知識(shí)梳理(2) - synchronized 三部曲之基本使用

一、為什么要使用 synchronized

使用synchronized的原因在于:它能夠確保多個(gè)線程在同一時(shí)刻躏嚎,只能有一個(gè)線程處于方法或者同步塊中,它保證了線程對(duì)變量訪問(wèn)的可見(jiàn)性和排他性。

二堡牡、synchronized 原理

JDK 1.6之前则涯,synchronized的實(shí)現(xiàn)是基于對(duì)象上的監(jiān)視器复局,這也被稱(chēng)為重量鎖。默認(rèn)情況下粟判,每一個(gè)對(duì)象都有一個(gè)關(guān)聯(lián)的Monitor亿昏,而每個(gè)Monitor包含了一個(gè)EntryCount計(jì)數(shù)器,它是synchronized實(shí)現(xiàn)可重入的關(guān)鍵档礁。

JDK 1.6之后角钩,對(duì)鎖進(jìn)行了一系列優(yōu)化的措施,通過(guò)引入自旋鎖呻澜、適應(yīng)性自旋鎖递礼、鎖消除、鎖粗化羹幸、偏向鎖脊髓、輕量級(jí)鎖等技術(shù)來(lái)減少鎖操作的開(kāi)銷(xiāo)。

這些優(yōu)化措施最終的目的是減少鎖操作的開(kāi)銷(xiāo)栅受,然而它所改變的只是鎖的實(shí)現(xiàn)方式将硝,但是加鎖和解鎖這一基本原則是沒(méi)有改變的恭朗。這篇文章主要是介紹synchronized的使用,因此依疼,在后面的介紹中痰腮,我們還是按照比較容易理解的重量鎖的方式進(jìn)行分析,在之后的文章中律罢,我們?cè)賮?lái)談一下優(yōu)化后的實(shí)現(xiàn)策略膀值。

2.1 進(jìn)入同步方法或者代碼塊

當(dāng)一個(gè)線程執(zhí)行某個(gè)對(duì)象的同步方法或者代碼塊時(shí),會(huì)先檢查這個(gè)對(duì)象所關(guān)聯(lián)的Monitor's EntryCount是否為0

  • 如果EntryCount0弟翘,那么該線程就會(huì)將Monitor’s EntryCount設(shè)置為1虫腋,并成為該Monitor的所有者,接著執(zhí)行該方法或者代碼塊中的語(yǔ)句稀余。
  • 如果EntryCount不為0悦冀,這時(shí)會(huì)去檢查對(duì)象所關(guān)聯(lián)的Monitor的持有者是哪一個(gè)線程:
  • 第一種情況:持有該Monitor的線程就是當(dāng)前正在嘗試獲取Monitor的線程,那么將EntryCount的數(shù)值加1睛琳,繼續(xù)執(zhí)行方法或者代碼塊中的語(yǔ)句盒蟆。
  • 第二種情況:持有該Monitor的是其它的線程,那么該線程進(jìn)入阻塞狀態(tài)师骗,直到EntryCount的數(shù)值變?yōu)?code>0历等。

2.2 退出同步方法或者代碼塊

當(dāng)一個(gè)線程從同步方法或者代碼塊退出時(shí),會(huì)將EntryCount1辟癌,如果EntryCount變?yōu)?code>0寒屯,那么該線程會(huì)釋放它所持有的Monitor。之前那些阻塞在synchronized的線程會(huì)嘗試去獲取Monitor黍少,成功獲取Monitor的線程可以進(jìn)入同步方法或者代碼塊寡夹。

三、synchronized 使用

對(duì)于synchronized的使用厂置,我們有兩種分類(lèi)方法:

  • 根據(jù)使用場(chǎng)景分類(lèi)
  • 根據(jù)Monitor關(guān)聯(lián)的對(duì)象分類(lèi)菩掏。

3.1 根據(jù)使用場(chǎng)景分類(lèi)

很多介紹synchronized的文章,都是通過(guò)使用場(chǎng)景進(jìn)行分類(lèi)的昵济,一般來(lái)說(shuō)可以分為如下四種使用場(chǎng)景智绸,而每種場(chǎng)景下根據(jù)Monitor所關(guān)聯(lián)的對(duì)象不同,又會(huì)衍生出另外的用法:

  • 靜態(tài)方法
    //靜態(tài)方法访忿,使用的是Class類(lèi)鎖
    synchronized public static void staticMethod() {}
  • 靜態(tài)方法代碼塊
    private static final byte[] mStaticLockByte = new byte[1];

    //靜態(tài)方法代碼塊1瞧栗,使用的是Class類(lèi)鎖
    public static void staticBlock1() {
        synchronized (SynchronizedObject.class) {}
    }

    //靜態(tài)方法代碼塊2,使用的是內(nèi)部靜態(tài)變量鎖
    public static void staticBlock2() {
        synchronized (mStaticLockByte) {} 
    }
  • 普通方法
    //普通方法醉顽,使用的是調(diào)用該方法的對(duì)象鎖
    synchronized public void method() {}
  • 普通方法代碼塊
    private static final byte[] mStaticLockByte = new byte[1];
    private final byte[] mLockByte = new byte[1];

    //普通方法代碼塊1沼溜,使用的是Class類(lèi)鎖
    public void block1() {
        synchronized (SynchronizedObject.class) {}
    }

    //普通方法代碼塊2,使用的是mLockByte的變量鎖
    public void block2() {
        synchronized (mLockByte) {} //變量需要聲明為final
    }
    
    //普通方法代碼塊3游添,使用的是mStaticLockByte的變量鎖
    public void block3() {
        synchronized (mStaticLockByte) {} 
    }

    //普通方法代碼塊4系草,使用的是調(diào)用該方法的對(duì)象鎖
    public void block4() {
        synchronized (this) {}
    }

3.2 根據(jù) Monitor 關(guān)聯(lián)的對(duì)象分類(lèi)

根據(jù)使用場(chǎng)景進(jìn)行分類(lèi)通熄,主要是為了讓大家知道如何使用synchronized關(guān)鍵字,然而要真正地理解synchronized找都,就需要結(jié)合第二節(jié)談到的synchronized原理唇辨,其實(shí)3.1中談到的多種場(chǎng)景,都是和Monitor有關(guān)能耻,那么從和Monitor關(guān)聯(lián)的對(duì)象來(lái)看赏枚,我們重新對(duì)3.1中的8種場(chǎng)景重新進(jìn)行分類(lèi):

  • Class對(duì)象:
  • 靜態(tài)方法
  • 靜態(tài)方法代碼塊1 - SynchronizedObject.class
  • 普通方法代碼塊1 - SynchronizedObject.class
  • 調(diào)用方法的對(duì)象
  • 普通方法
  • 普通方法代碼塊4 - this
  • 靜態(tài)對(duì)象
  • 靜態(tài)方法代碼塊2 - mStaticLockByte
  • 普通方法代碼塊3 - mStaticLockByte
  • 非靜態(tài)對(duì)象
  • 普通方法代碼塊1 - mLockByte

如果使用場(chǎng)景屬于上面的同一個(gè)分類(lèi)當(dāng)中,那么才有可能產(chǎn)生線程阻塞在synchronized關(guān)鍵字的情況晓猛,舉一個(gè)例子饿幅,如果A線程通過(guò)靜態(tài)方法訪問(wèn)(分類(lèi)一)并且沒(méi)有從該方法退出:

  • 這時(shí)B線程是通過(guò)一個(gè)對(duì)象的普通方法來(lái)訪問(wèn)(分類(lèi)二),那么是不會(huì)阻塞的戒职,這是因?yàn)檎{(diào)用該方法的對(duì)象所關(guān)聯(lián)的Monitor沒(méi)有被持有栗恩。
  • 如果B線程使用的是靜態(tài)方法代碼塊來(lái)訪問(wèn),而該靜態(tài)方法代碼塊使用的是SynchronizedObject.class來(lái)修飾(分類(lèi)一)洪燥,由于這兩種使用場(chǎng)景是屬于同一個(gè)分類(lèi)磕秤,那么就會(huì)B線程就會(huì)進(jìn)入阻塞狀態(tài),這是因?yàn)?code>SynchronizedObject類(lèi)所關(guān)聯(lián)的Monitor已經(jīng)被A線程持有了捧韵。

四市咆、小結(jié)

從表面上來(lái)看,synchronized的使用可以簡(jiǎn)單地分為同步方法和同步代碼塊再来,但是究竟在什么情況下會(huì)導(dǎo)致一個(gè)線程在synchronized上阻塞蒙兰,則需要分析synchronized方法所嘗試獲取的Monitor的是否已經(jīng)被其它線程持有了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末芒篷,一起剝皮案震驚了整個(gè)濱河市癞己,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌梭伐,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,682評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件仰担,死亡現(xiàn)場(chǎng)離奇詭異糊识,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)摔蓝,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)赂苗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人贮尉,你說(shuō)我怎么就攤上這事拌滋。” “怎么了猜谚?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,083評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵败砂,是天一觀的道長(zhǎng)赌渣。 經(jīng)常有香客問(wèn)我,道長(zhǎng)昌犹,這世上最難降的妖魔是什么坚芜? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,763評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮斜姥,結(jié)果婚禮上鸿竖,老公的妹妹穿的比我還像新娘。我一直安慰自己铸敏,他們只是感情好缚忧,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著杈笔,像睡著了一般闪水。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上桩撮,一...
    開(kāi)封第一講書(shū)人閱讀 51,624評(píng)論 1 305
  • 那天敦第,我揣著相機(jī)與錄音,去河邊找鬼店量。 笑死芜果,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的融师。 我是一名探鬼主播右钾,決...
    沈念sama閱讀 40,358評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼旱爆!你這毒婦竟也來(lái)了舀射?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,261評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤怀伦,失蹤者是張志新(化名)和其女友劉穎脆烟,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體房待,經(jīng)...
    沈念sama閱讀 45,722評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡邢羔,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了桑孩。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片拜鹤。...
    茶點(diǎn)故事閱讀 40,030評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖流椒,靈堂內(nèi)的尸體忽然破棺而出敏簿,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 35,737評(píng)論 5 346
  • 正文 年R本政府宣布惯裕,位于F島的核電站温数,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏轻猖。R本人自食惡果不足惜帆吻,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望咙边。 院中可真熱鬧猜煮,春花似錦、人聲如沸败许。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,941評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)市殷。三九已至愕撰,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間醋寝,已是汗流浹背搞挣。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,057評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留音羞,地道東北人囱桨。 一個(gè)月前我還...
    沈念sama閱讀 48,237評(píng)論 3 371
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像嗅绰,于是被迫代替她去往敵國(guó)和親舍肠。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評(píng)論 2 355

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