帶你真的理解synchronize的對(duì)象鎖和類鎖的使用

先來(lái)簡(jiǎn)單理解一下對(duì)象鎖和類鎖:

Java對(duì)象鎖

對(duì)象鎖是用于對(duì)象實(shí)例方法硅则,或者一個(gè)對(duì)象實(shí)例上的

有一個(gè)類A,A里面有一些方法或者代碼塊使用了對(duì)象鎖。如:

class A{
    //同步方法
    public void test1() {
        synchronized (this) {
            
        }
    }
    //跟上面的test1方法一樣都是對(duì)象鎖,只是鎖的尺寸不同
    public synchronized void test2() {
       
    }
    //方法二
    public void test3() {
        
    }
}

現(xiàn)在有線程1new了一個(gè)A的對(duì)象昼汗,對(duì)象為a,并調(diào)用了使用對(duì)象鎖方法test1()旺坠,即:

A a = new A();
a.test1();
---到此是線程1執(zhí)行的代碼---

此時(shí)當(dāng)線程1在執(zhí)行加了對(duì)象鎖的同步方法test1的那一刻乔遮,這時(shí)又有一個(gè)線程2過(guò)來(lái)扮超,想要執(zhí)行下面這段代碼會(huì)怎么樣呢取刃?

a.test2();
---到此是線程2執(zhí)行的代碼---

如果是正常的多線程場(chǎng)景蹋肮,同一時(shí)刻,線程1執(zhí)行a.test1()和線程2執(zhí)行a.test2()是互不影響的璧疗。

但是這里的線程2必須等線程1釋放對(duì)象鎖之后才可以執(zhí)行test2()坯辩,因?yàn)椋?/strong>

test1()方法加了synchronized對(duì)象鎖,那在線程1執(zhí)行對(duì)象a的test1()方法時(shí)崩侠,就會(huì)鎖住對(duì)象實(shí)例a的內(nèi)存漆魔,在線程1還沒(méi)釋放對(duì)象鎖之前,任何線程都是沒(méi)辦法進(jìn)入對(duì)象a里面的却音。而線程1只會(huì)在執(zhí)行完同步方法或者同步代碼塊只會(huì)才會(huì)釋放對(duì)象鎖改抡。

但,如果線程2做的是這么一個(gè)操作:

a.test3();

這個(gè)時(shí)候線程3執(zhí)行test2方法就不需要等待線程1系瓢,進(jìn)行了同步的方法(加鎖方法)和沒(méi)有進(jìn)行同步的方法(普通方法)是互不影響的阿纤,一個(gè)線程進(jìn)入了同步方法,得到了對(duì)象鎖夷陋,其他線程還是可以訪問(wèn)那些沒(méi)有同步的方法(普通方法)欠拾。這里涉及到內(nèi)置鎖的一個(gè)概念(此概念出自java并發(fā)編程實(shí)戰(zhàn)第二章):

對(duì)象的內(nèi)置鎖和對(duì)象的狀態(tài)之間是沒(méi)有內(nèi)在的關(guān)聯(lián)的,雖然大多數(shù)類都將內(nèi)置鎖用做一種有效的加鎖機(jī)制骗绕,但對(duì)象的域并不一定通過(guò)內(nèi)置鎖來(lái)保護(hù)藐窄。當(dāng)獲取到與對(duì)象關(guān)聯(lián)的內(nèi)置鎖時(shí),并不能阻止其他線程訪問(wèn)該對(duì)象酬土,當(dāng)某個(gè)線程獲得對(duì)象的鎖之后荆忍,只能阻止其他線程獲得同一個(gè)鎖。之所以每個(gè)對(duì)象都有一個(gè)內(nèi)置鎖撤缴,是為了免去顯式地創(chuàng)建鎖對(duì)象东揣。

在微服務(wù)的后端中,每個(gè)不同的請(qǐng)求都會(huì)新建一個(gè)對(duì)象來(lái)handle腹泌,理論上對(duì)象鎖是不會(huì)造成我們想要的約束的

Java類鎖

類鎖是用于類的靜態(tài)方法或者一個(gè)類的class對(duì)象上的

同樣的例子嘶卧,有一個(gè)類A,只是A里面使用synchronize的方法不一樣了凉袱,這種使用方法會(huì)鎖住類A芥吟。如:

class A{
    //同步方法
    public void test1() {
        synchronized (A.class) {
            
        }
    }
    //跟上面的同步方法一樣,都是類鎖专甩,只是表現(xiàn)形式不同
    public static synchronized void test2() {
        
    }
    public synchronized void test3() {
        
    }
}

現(xiàn)在有線程1new了一個(gè)A的對(duì)象钟鸵,對(duì)象為a,并調(diào)用了使用對(duì)象鎖方法test1()涤躲,即:

A a = new A();
a.test1();
---到此是線程1執(zhí)行的代碼---

此時(shí)當(dāng)線程1在執(zhí)行加了對(duì)象鎖的同步方法test1的那一刻棺耍,這時(shí)又有一個(gè)線程2過(guò)來(lái),想要執(zhí)行下面這段代碼會(huì)怎么樣呢种樱?

A.test2();
---到此是線程2執(zhí)行的代碼---

這里的線程2必須等線程1釋放類鎖之后才可以執(zhí)行A.test2()蒙袍,因?yàn)椋?/strong>

線程1執(zhí)行的test1()方法里面鎖住了A.class俊卤,也就是鎖住了類A的內(nèi)存。那同一時(shí)刻所有實(shí)例想使用test1方法或者是其他加了類鎖的形如A.test2()方法害幅,都得等線程1釋放類鎖后才能執(zhí)行消恍。線程2要用加了類鎖的靜態(tài)方法test2,那自然是用不了了以现。

想一下狠怨,如果是在高并發(fā)的情況下,所有要執(zhí)行類A的test1請(qǐng)求都得阻塞等待最先進(jìn)入類A的類鎖的線程執(zhí)行完邑遏,釋放類鎖后佣赖,才能執(zhí)行。如果這個(gè)鎖住的方法執(zhí)行的時(shí)候過(guò)長(zhǎng)记盒,或者直接死循環(huán)茵汰,那整個(gè)系統(tǒng)將會(huì)被拖垮甚至癱瘓。

但孽鸡,如果線程2做的是這么一個(gè)操作:

a.test3();

結(jié)果是線程1執(zhí)行了類鎖的同步方法蹂午,線程2執(zhí)行了對(duì)象鎖的同步方法,兩者互不影響彬碱。這證明了類鎖和對(duì)象鎖是兩個(gè)不一樣的鎖豆胸,控制著不同的區(qū)域,它們是互不干擾的巷疼。同樣晚胡,線程獲得對(duì)象鎖的同時(shí),也可以獲得該類鎖嚼沿,即同時(shí)獲得兩個(gè)鎖估盘,這是允許的。

在微服務(wù)的后端中骡尽,我們常用類鎖來(lái)進(jìn)行約束

其實(shí)總結(jié)起來(lái)很簡(jiǎn)單:

  • 一個(gè)鎖的是類對(duì)象遣妥,一個(gè)鎖的是實(shí)例對(duì)象。
  • 若類對(duì)象被lock攀细,則類對(duì)象的所有同步方法全被lock箫踩;
  • 若實(shí)例對(duì)象被lock,則該實(shí)例對(duì)象的所有同步方法全被lock
到這里大家應(yīng)該對(duì)對(duì)象鎖和類鎖應(yīng)該有個(gè)更加清晰的理解了

注意:

上面我們有講到synchronize的一個(gè)缺陷谭贪,就是如果同步的方法死循環(huán)了或者執(zhí)行時(shí)間過(guò)長(zhǎng)了境钟,會(huì)影響系統(tǒng)的正常運(yùn)行。那么為了將這種風(fēng)險(xiǎn)降到最低俭识,一般我們使用類鎖的時(shí)候慨削,不會(huì)直接synchronize(xx.class)或者static synchronized去鎖住這個(gè)類的所有同步方法,而是用先在這個(gè)類里面聲明了一個(gè)對(duì)象實(shí)例:Object object=new Object(),然后再synchronize(object)缚态。那么這個(gè)方法加鎖的對(duì)象是object這個(gè)對(duì)象磁椒,當(dāng)一個(gè)線程執(zhí)行這個(gè)方法時(shí),這對(duì)其他線程要執(zhí)行這個(gè)類的其他同步方法是沒(méi)有影響的猿规,只會(huì)影響到要執(zhí)行用synchronize(object)鎖住的方法,因?yàn)樗麄兂钟械逆i都完全不一樣宙橱。


總結(jié)五種用法:

一姨俩、this

synchronized(this){ 
//互斥代碼
}

這里的this指的是執(zhí)行這段代碼的對(duì)象,synchronized得到的鎖就是this這個(gè)對(duì)象的鎖

public synchronized void func(){ 
//互斥代碼
}

二师郑、A.class

synchronized(A.class){ 
//互斥代碼
}

這里A.class得到的是A這類环葵,所以synchronized關(guān)鍵字得到的鎖是類的鎖,這種方法同下面的方法功能是相同的:

public static synchronized void fun(){ 
//互斥代碼
}

所有需要類的鎖的方法都不能同時(shí)執(zhí)行宝冕,但是它和需要某個(gè)對(duì)象的鎖的方法或者是不需要任何鎖的方法可以同時(shí)執(zhí)行张遭。

三、object.getClass()

synchronized(object.getClass){ 
//互斥代碼
}

這種方法一般情況下同第二種是相同地梨,但是出現(xiàn)繼承和多態(tài)時(shí)菊卷,得到的結(jié)果卻是不相同的。所以一般情況下推薦使用A.class的方式宝剖。

四洁闰、object

private Object lock = new Object();
public void test1(){
    synchronized(lock){ 
    //互斥代碼
    }
}

這里synchronized關(guān)鍵字拿到的鎖是對(duì)象object的鎖,所有需要這個(gè)對(duì)象的鎖的方法都不能同時(shí)執(zhí)行万细。這是最常用的高并發(fā)場(chǎng)景下要鎖住某個(gè)方法所用的操作扑眉。

五、static object

上邊的代碼稍作修改就可以起到互斥作用赖钞,將類中Object對(duì)象的聲明改為下面這樣:

private static Object lock = new Object();

這樣不同的類使用的就是同一個(gè)object對(duì)象腰素,需要的鎖也是同一個(gè)鎖,就可以達(dá)到互斥的效果了雪营。

碼字不易弓千,轉(zhuǎn)發(fā)請(qǐng)附帶出處。如果喜歡我的文章献起,可以點(diǎn)贊關(guān)注计呈,多多支持我哦!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末征唬,一起剝皮案震驚了整個(gè)濱河市捌显,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌总寒,老刑警劉巖扶歪,帶你破解...
    沈念sama閱讀 221,548評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡善镰,警方通過(guò)查閱死者的電腦和手機(jī)妹萨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)炫欺,“玉大人乎完,你說(shuō)我怎么就攤上這事∑仿澹” “怎么了树姨?”我有些...
    開(kāi)封第一講書人閱讀 167,990評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)桥状。 經(jīng)常有香客問(wèn)我帽揪,道長(zhǎng),這世上最難降的妖魔是什么辅斟? 我笑而不...
    開(kāi)封第一講書人閱讀 59,618評(píng)論 1 296
  • 正文 為了忘掉前任转晰,我火速辦了婚禮,結(jié)果婚禮上士飒,老公的妹妹穿的比我還像新娘查邢。我一直安慰自己,他們只是感情好酵幕,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,618評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布侠坎。 她就那樣靜靜地躺著,像睡著了一般裙盾。 火紅的嫁衣襯著肌膚如雪实胸。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 52,246評(píng)論 1 308
  • 那天番官,我揣著相機(jī)與錄音庐完,去河邊找鬼。 笑死徘熔,一個(gè)胖子當(dāng)著我的面吹牛门躯,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播酷师,決...
    沈念sama閱讀 40,819評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼讶凉,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了山孔?” 一聲冷哼從身側(cè)響起懂讯,我...
    開(kāi)封第一講書人閱讀 39,725評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎台颠,沒(méi)想到半個(gè)月后褐望,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,268評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,356評(píng)論 3 340
  • 正文 我和宋清朗相戀三年瘫里,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了实蔽。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,488評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡谨读,死狀恐怖局装,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情劳殖,我是刑警寧澤铐尚,帶...
    沈念sama閱讀 36,181評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站闷尿,受9級(jí)特大地震影響塑径,放射性物質(zhì)發(fā)生泄漏女坑。R本人自食惡果不足惜填具,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,862評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望匆骗。 院中可真熱鬧劳景,春花似錦、人聲如沸碉就。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,331評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)瓮钥。三九已至筋量,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間碉熄,已是汗流浹背桨武。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,445評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留锈津,地道東北人呀酸。 一個(gè)月前我還...
    沈念sama閱讀 48,897評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像琼梆,于是被迫代替她去往敵國(guó)和親性誉。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,500評(píng)論 2 359

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