Java并發(fā)編程(二)synchronized關(guān)鍵字

注意

以下內(nèi)容源自互聯(lián)網(wǎng)相關(guān)資料及本人學(xué)習(xí)與工作經(jīng)驗演训,僅為學(xué)習(xí)及技術(shù)分享所用岛抄,切勿用于商業(yè)用途,轉(zhuǎn)載請注明出處。

1. 線程同步

多個線程之間可能會競爭相同的資源录肯,比如兩個讀取數(shù)據(jù)庫操作的線程就會競爭數(shù)據(jù)庫連接這個資源驴一,這個被競爭的資源叫作共享資源或者臨界資源梳虽。如何協(xié)調(diào)各個線程對共享資源的使用楼入,稱為線程同步。線程同步需要考慮以下幾點:

  • 存在競爭就需要同步要销,同步的概念指的不是同時執(zhí)行构回,而是協(xié)同步調(diào),按一定的規(guī)矩將線程“排隊”疏咐,確定好“誰先消費共享資源”纤掸,而這個規(guī)矩必須滿足于業(yè)務(wù)的要求。
  • 共享資源才需同步凳鬓,只有共享資源的讀寫訪問才需要同步茁肠。如果不是共享資源,那么就根本沒有同步的必要缩举。
  • 只對“變量”進行同步,只有“變量”(這里的變量指的是資源存在可變性)才需要同步訪問匹颤。如果共享的資源是固定不變的仅孩,那么就相當(dāng)于“常量”,線程同時讀取常量也不需要同步印蓖。至少一個線程修改共享資源辽慕,這樣的情況下,線程之間就需要同步赦肃。
  • 共享資源并非同份代碼溅蛉,多個線程訪問共享資源的代碼有可能是同一份代碼公浪,也有可能是不同的代碼;無論是否執(zhí)行同一份代碼船侧,只要這些線程的代碼訪問同一份可變的共享資源欠气,這些線程之間就需要同步。

2. synchronized關(guān)鍵字

Java提供了原生的synchronized關(guān)鍵字來修飾臨界資源镜撩,對共享資源加鎖预柒,使同一時間只能有一個線程得到共享資源,其它線程只能阻塞等待該線程釋放共享資源后袁梗,才可以重新競爭獲得共享資源的機會宜鸯。
有一個線典的例子:多個人上公廁,假設(shè)只有一個坑位遮怜,這里的坑位就是共享資源淋袖,多個人就是多個線程,同時只能有一個人競爭得到上坑的機會锯梁,上坑后即碗,這個人會把廁所門鎖上,其他人只能在外等這個人上完廁所后涝桅,打開廁所后拜姿,才能“蜂擁而上”競爭下一次上坑的機會。在這個例子里冯遂,廁所門鎖就相當(dāng)于synchronized關(guān)鍵字蕊肥,它將廁所這個共享資源加上了鎖,同時能允許一個線程進入蛤肌。

2.1 用法1 synchronized修飾實例方法

synchronized修飾實例方法壁却,鎖是加在這個方法的實例對象上的,當(dāng)多個線程訪問同一個實例對象的這個方法時裸准,只能有一個線程進入該方法展东。注意:這種場景下,一個實例對象對應(yīng)一把鎖炒俱,多個線程只有調(diào)用同一個實例對象時才有意義盐肃。
下面的代碼是synchroinzed修飾實例方法的例子:

public synchronized void addCount(){
        for(int i = 0;i<50;i++){
            count +=1;
        }
    }

2.2 用法2 synchronized修飾靜態(tài)方法

synchronized修飾靜態(tài)方法與修飾實例方法在語法上是相同的,參見下例:

public synchronized static void addCount(){
        for(int i = 0;i<50;i++){
            count +=1; //count必須為靜態(tài)變量
        
        }
    }

我們知道权悟,在JVM中每一個類只存在一個類對象(class object)砸王,在這種場景下,synchronized所加的鎖就在修飾的靜態(tài)方法所屬的類對象上峦阁,所有線程調(diào)用此靜態(tài)方法時谦铃,同一時間只有一個線程能獲得這把鎖,進行這個靜態(tài)方法榔昔。

2.3 用法3 synchronized修飾實例方法內(nèi)代碼塊

上面示例代碼中驹闰,共享資源其實只是count這個變量瘪菌,我們沒有必要對整個方法加鎖,這樣反而會影響整個程序的執(zhí)行效率嘹朗,這時候师妙,我們可以將synchronized關(guān)鍵字加在操作count變量的代碼塊上,實現(xiàn)更細粒度的控制骡显。如下:

public void addCount(){
        for(int i = 0;i<50;i++){
            synchronized(this){
                          count +=1;
                        }
        }
    }

synchronized修飾代碼塊時疆栏,需要指定一個“監(jiān)視對象”(monitor object),也就是要對哪個對象加鎖惫谤。上面示例代碼中使用this指向本實例對象壁顶,表示對實例對象加鎖,多個線程訪問此實例對象時溜歪,只能有一個線程進行synchronized修飾的代碼塊若专。
監(jiān)視對象不一定要是this,也可以是任何對象蝴猪,如下例所示:

public final Object monitor = new Object();//final修飾调衰,表示監(jiān)視對象不可變
public void addCount(){
        for(int i = 0;i<50;i++){
            synchronized(monitor){
                          count +=1;
                        }
            
        }
    }

上例中,我們用final修飾了監(jiān)視對象自阱,為什么呢嚎莉?因為monitor這個變量實際是只是指向監(jiān)視對象所在內(nèi)存中的地址,如果不修飾成final的話沛豌,當(dāng)我們修改這個monitor變量趋箩,讓它指向其他對象,比如 在synchronized代碼塊中加派,我們讓monitor指向其他對象(monitor = new OtherObject();) 那么monitor就不是原本我們指定的監(jiān)視對象了叫确,鎖也就失去了意義。
如果監(jiān)視對象不是同一個實例對象的話芍锦,則表示有多個不同的鎖竹勉,不同的線程可以進入不同的鎖限制的代碼塊。

2.4 用法4 synchronized修飾靜態(tài)方法內(nèi)代碼塊

同樣也可以使用synchronized來修飾靜態(tài)方法內(nèi)的代碼塊娄琉,此時監(jiān)視對象必須是類對象(class object)次乓。
注意,如果監(jiān)視的類對象不同孽水,則表示有多個不同的鎖檬输,不同的線程可以進入不同的鎖限制的代碼塊。

public synchronized static void addCount(){
        for(int i = 0;i<50;i++){
                synchronized(SynchronizedUsage.class){//SynchronizedUsage.class是類對象
            count +=1; //count必須為靜態(tài)變量
                 }
        }
    }

2.5 釋放鎖的兩種情況

如果一個代碼塊被synchronized修飾了匈棘,當(dāng)一個線程獲取了對應(yīng)的鎖,并執(zhí)行該代碼塊時析命,其他線程便只能一直等待主卫,等待獲取鎖的線程釋放鎖逃默,而這里獲取鎖的線程釋放鎖只會有兩種情況:

  • 獲取鎖的線程執(zhí)行完了該代碼塊,然后線程釋放對鎖的占有簇搅。
  • 線程執(zhí)行發(fā)生異常完域,此時JVM會讓線程自動釋放鎖。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末瘩将,一起剝皮案震驚了整個濱河市吟税,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌姿现,老刑警劉巖肠仪,帶你破解...
    沈念sama閱讀 217,907評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異备典,居然都是意外死亡异旧,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評論 3 395
  • 文/潘曉璐 我一進店門提佣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來吮蛹,“玉大人,你說我怎么就攤上這事拌屏〕闭耄” “怎么了?”我有些...
    開封第一講書人閱讀 164,298評論 0 354
  • 文/不壞的土叔 我叫張陵倚喂,是天一觀的道長每篷。 經(jīng)常有香客問我,道長务唐,這世上最難降的妖魔是什么雳攘? 我笑而不...
    開封第一講書人閱讀 58,586評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮枫笛,結(jié)果婚禮上吨灭,老公的妹妹穿的比我還像新娘。我一直安慰自己刑巧,他們只是感情好喧兄,可當(dāng)我...
    茶點故事閱讀 67,633評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著啊楚,像睡著了一般吠冤。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上恭理,一...
    開封第一講書人閱讀 51,488評論 1 302
  • 那天拯辙,我揣著相機與錄音,去河邊找鬼。 笑死涯保,一個胖子當(dāng)著我的面吹牛诉濒,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播夕春,決...
    沈念sama閱讀 40,275評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼未荒,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了及志?” 一聲冷哼從身側(cè)響起片排,我...
    開封第一講書人閱讀 39,176評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎速侈,沒想到半個月后率寡,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,619評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡锌畸,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,819評論 3 336
  • 正文 我和宋清朗相戀三年勇劣,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片潭枣。...
    茶點故事閱讀 39,932評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡比默,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出盆犁,到底是詐尸還是另有隱情命咐,我是刑警寧澤,帶...
    沈念sama閱讀 35,655評論 5 346
  • 正文 年R本政府宣布谐岁,位于F島的核電站醋奠,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏伊佃。R本人自食惡果不足惜窜司,卻給世界環(huán)境...
    茶點故事閱讀 41,265評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望航揉。 院中可真熱鬧塞祈,春花似錦、人聲如沸帅涂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽媳友。三九已至斯议,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間醇锚,已是汗流浹背哼御。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人艇搀。 一個月前我還...
    沈念sama閱讀 48,095評論 3 370
  • 正文 我出身青樓尿扯,卻偏偏與公主長得像,于是被迫代替她去往敵國和親焰雕。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,884評論 2 354

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