Synchronized 詳解

synchronized關(guān)鍵字采用對代碼塊/方法體加鎖的方式解決Java中多線程訪問同一個資源時针饥,引起的資源沖突問題洲守。

synchronized 同步鎖可分為兩種類型,四種表現(xiàn)形式

  • 對象鎖: 對單個實例對象的獨享內(nèi)存的部分區(qū)域加鎖
    • 修飾非靜態(tài)方法
    • 修飾代碼塊
  • 類鎖: 對整個類的共享內(nèi)存的部分區(qū)域加鎖
    • 修飾靜態(tài)方法
    • 修飾代碼塊

Find Two Object

沃茲吉索得: 面向?qū)ο缶幊痰木柙谟谫N合實際眷射,更容易建立易于理解的對象模型挖腰。比如設(shè)計模式用于面向?qū)ο蟮木幊堂黠@更加易于理解雕沿。 :)

  1. 首先我們定義一個Human類:
public class Human {
    //所有的Human都有吃晚飯這個動作
    public void eatDinner() {
        pickupByLeftHand(); //用左手拿起食物
        eatFoodByMouth(); //用嘴吃食物
    };
    //所有的Human都有喝水這個動作
    public void drinkWater() {
        pickupByRightHand(); //用右手拿起水
        drinkWaterByMouth();   //用嘴喝水
    } 
    //看電視
    public void watchTV() {
    }
}
  1. 然后我們實例化兩個對象:
Human XiaoMing = new Human();  //小明
Human XiaoMingTaBa = new Human();  //小明他爸

Let's have dinner!

小明要吃晚飯了 XiaoMing.eatDinner() , 忽然他又想喝水了 XiaoMing.drinkWater()曙聂。好吧晦炊,他只有一張嘴鞠鲜,同時又喝水又吃飯會被嗆到吧宁脊?這時我們想了個解決辦法:

//使用 synchronized 關(guān)鍵字修飾 eatDinner() 
public synchronized void eatDinner() {
    pickupByHand(); //用手拿起食物
    eatFoodByMouth(); //用嘴吃食物
}
//使用 synchronized 關(guān)鍵字修飾 drinkWater
public synchronized void eatDinner() {
    pickupByHand(); //用手拿起水
    drinkWaterByMouth();   //用嘴喝水
}

現(xiàn)在當小明在吃飯的時候,他想喝水了贤姆,由于我們使用了synchronized修飾這兩個動作榆苞。小明在喝水之前會先把飯吃完再執(zhí)行喝水的動作。這樣就解決了沖突的問題霞捡。
再來分析下watchTV()這個動作:由于這個動作和吃晚飯喝水并沒有沖突可以同時進行坐漏,所以我們并不需要synchronized關(guān)鍵字來對它進行修飾。

當我們調(diào)用synchronized修飾的非靜態(tài)方法時碧信,所有采用了synchronized修飾的同步方法都會被鎖定赊琳,所有沒有采用synchronized修飾的非同步方法仍然可以執(zhí)行。

現(xiàn)在我們來探討一下小明他爸吃飯喝水的問題:雖然我們對小明的eatDinner()方法和drinkWater()方法進行了同步鎖定砰碴,但是顯而易見的是躏筏。小明喝水吃飯的動作并不影響小明他爸喝水吃飯的動作。所以我們可以對上面的結(jié)論進行完善:

Conclusion1: 使用 synchronized修飾非靜態(tài)方法
當我們通過某個實例對象A(XiaoMing)訪問非靜態(tài)同步方法(eat or drink)時呈枉,所有通過對象A訪問非靜態(tài)同步方法(eat or drink)的操作都會被阻塞直至另一個操作執(zhí)行完畢趁尼,而所有通過對象A訪問非靜態(tài)同步方法的操作(watchTV)仍然可以執(zhí)行。而當我們通過對象A訪問某個同步方法時猖辫,仍然可以通過對象B訪問任意一個同步方法酥泞。(即小明吃飯喝水不影響小明他爸吃飯喝水

Let's have dinner 再來一次!

現(xiàn)在我們來分析另一種吃飯喝水的情況啃憎。小明和小明他爸一起在吃飯芝囤,兩個人都想喝水了,但是桌子上這時只有1瓶水了,這瓶水兩個人誰先搶到誰就能喝悯姊。小明的經(jīng)驗告訴他吃飯的同時如果喝水的話會被嗆到名党,所以他只好先把飯吃完再去喝水。而小明他爸吃過的鹽比小明吃過的米還多, 經(jīng)驗豐富的他知道吃飯時喝水會被嗆到是因為我們只有一張嘴,可是我們有兩只手啊挠轴。所以他的吃飯和喝水的動作是這樣實現(xiàn)的:

public void eatDinner() {
    pickupByLeftHand(); //用手拿起食物
    synchronized (mouth) {
        eatFoodByMouth(); //用嘴吃食物
    }
};
public void drinkWater() {
    pickupByRightHand(); //用手拿起水
    synchronized (mouth) {
        drinkWaterByMouth();   //用嘴喝水
    }
}

所以他在吃飯的同時传睹,用手拿起了水。好吧岸晦,雖然小明和小明他爸吃飯速度差不多欧啤,但是當大家都吃完飯的時候水已經(jīng)在小明他爸手里了。启上。邢隧。。(小明目瞪口呆.jpg)
總的吃飯時間計時是這樣的:(如果不存在競爭關(guān)系)
小明:timeOf(用右手拿起食物) + timeOf(用嘴吃食物) + timeOf(用左手拿起水) + timeOf(喝水)
小明他爸:imeOf(用右手拿起食物) + timeOf(用嘴吃食物冈在,同時可以用左手拿起水倒慧,而不增加吃食物的時間) + timeOf(喝水)
所以又得到了一個結(jié)論

**Conclusion2: **對象鎖的兩種形式的區(qū)別
這兩種形式?jīng)]有本質(zhì)上的不同。區(qū)別在于修飾代碼塊的形式盡可能的精簡了需要鎖住的同步代碼包券,使的我們的系統(tǒng)在高并發(fā)纫谅、資源競爭激烈的情況下更加高效。

關(guān)于類鎖

好吧溅固,我想不出類比的例子了付秕。直接說結(jié)論

Conclusion3: 類鎖(synchronized修飾靜態(tài)方法,synchronized(Human.class)修飾代碼塊)
訪問這兩種方式修飾的操作時侍郭,所有其他的采用synchronized修飾的靜態(tài)方法和采用synchronized(Human.this)修飾的代碼塊都會被鎖定(靜態(tài)的非同步方法不會被鎖定)询吴。但是不會影響到對象鎖,文章開頭有說明兩種鎖鎖住的內(nèi)存區(qū)域是不同的亮元!

Conclusion4: 類鎖的兩種形式的區(qū)別
參考對象鎖兩種形式的區(qū)別

The Last Supper

關(guān)于synchronized的兩種類型猛计,四種形式我們可以得出以下結(jié)論

  1. 當一個線程通過A對象訪問一個非靜態(tài)的同步方法(或同步代碼塊)時,其他線程通過A對象訪問非靜態(tài)同步方法(或同步代碼塊)的操作都會被鎖定爆捞。但是其他線程通過A對象訪問非靜態(tài)非同步方法的操作不會被鎖定奉瘤,而且通過B對象訪問非靜態(tài)同步方法的操作也不會被鎖。(因為各個對象的鎖是獨立的所以叫做對象鎖)
  2. 當一個線程訪問靜態(tài)同步方法或者由類鎖修飾的同步代碼塊時嵌削,所有該類的靜態(tài)方法或者被同一個類鎖修飾的同步代碼塊都會被鎖定毛好,其他線程無法訪問。
  3. 類鎖和對象鎖互不影響苛秕。
  4. 修飾方法和修飾代碼塊在本質(zhì)上是一樣的,區(qū)別只在于修飾代碼塊的方式在競爭激烈的情況下更加高效艇劫。
  5. 注意區(qū)別以下代碼的對象鎖的持有情況
public class Human {
    //XiaoMing.eatDinner();
    public synchronized void eatDinner() {   //這里的鎖是XiaoMing
        pickupByLeftHand();
        eatFoodByMouth();
    };
    
    //XiaoMing.eatDinner2();
    public void eatDinner() {
        synchronized(this) {    //這里的鎖是XiaoMing
            pickupByLeftHand();
            eatFoodByMouth();
        }
    };
    
    //XiaoMing.drinkWater();
    public void drinkWater() {
        pickupByRightHand();
        synchronized (mouth) {  //這里的鎖是mouth
            drinkWaterByMouth();
        }
    }
}

附:四種形式的鎖

  • 對象鎖: 對單個實例對象的獨享內(nèi)存的部分區(qū)域加鎖
    • 修飾非靜態(tài)方法
public synchronized void doSth() {}
  • 修飾代碼塊
public void doSth() {
      synchronized (obj) {
      }
}
  • 類鎖: 對整個類的共享內(nèi)存的部分區(qū)域加鎖
    • 修飾靜態(tài)方法
public static synchronized void doSth() {}
  • 修飾代碼塊
public void doSth() {
      synchronized (ClassA.class) {
      }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子蟹演,更是在濱河造成了極大的恐慌,老刑警劉巖酒请,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異羞反,居然都是意外死亡布朦,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進店門昼窗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來是趴,“玉大人,你說我怎么就攤上這事澄惊∷敉荆” “怎么了?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵掸驱,是天一觀的道長肛搬。 經(jīng)常有香客問我,道長亭敢,這世上最難降的妖魔是什么滚婉? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮帅刀,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘远剩。我一直安慰自己扣溺,他們只是感情好,可當我...
    茶點故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布瓜晤。 她就那樣靜靜地躺著锥余,像睡著了一般。 火紅的嫁衣襯著肌膚如雪痢掠。 梳的紋絲不亂的頭發(fā)上驱犹,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天,我揣著相機與錄音足画,去河邊找鬼雄驹。 笑死,一個胖子當著我的面吹牛淹辞,可吹牛的內(nèi)容都是我干的医舆。 我是一名探鬼主播,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼蔬将!你這毒婦竟也來了爷速?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤霞怀,失蹤者是張志新(化名)和其女友劉穎惫东,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體毙石,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡凿蒜,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了胁黑。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片废封。...
    茶點故事閱讀 39,965評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖丧蘸,靈堂內(nèi)的尸體忽然破棺而出漂洋,到底是詐尸還是另有隱情,我是刑警寧澤力喷,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站贝咙,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏庭猩。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一蔼水、第九天 我趴在偏房一處隱蔽的房頂上張望录肯。 院中可真熱鬧,春花似錦论咏、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽秀又。三九已至贬芥,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蘸劈,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工贤惯, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人孵构。 一個月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓烟很,卻偏偏與公主長得像,于是被迫代替她去往敵國和親雾袱。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,914評論 2 355

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

  • 一毒坛、概念 synchronized 是 Java 中的關(guān)鍵字林说,是利用鎖的機制來實現(xiàn)同步的。 鎖機制有如下兩種特性:...
    zly394閱讀 11,678評論 1 6
  • 1蝌数、了解synchronized synchronized是Java中的關(guān)鍵字,是一種同步鎖。當多個并發(fā)線程訪問同...
    黒貓閱讀 1,624評論 0 2
  • 在java多線程并發(fā)編程中對于 sychronized 大家一定不陌生饵撑,同步關(guān)鍵字 synchronized 是j...
    楊文杰閱讀 3,047評論 0 12
  • 由于同一進程的多個線程共享同一片存儲空間,在帶來方便的同時垢乙,也帶來了訪問沖突這個嚴重的問題。Java語言提供了專門...
    DanieX閱讀 16,368評論 7 16
  • 什么是Synchronized,有什么用? Java語言的關(guān)鍵字追逮,當它用來修飾一個方法或者一個代碼塊的時候,能夠保...
    phoenixsky閱讀 1,433評論 0 0