鍍金池/ 教程/ Java/ synchronized 關(guān)鍵字
并發(fā)新特性—信號(hào)量 Semaphore
線(xiàn)程間協(xié)作:wait、notify、notifyAll
notify 通知的遺漏
notifyAll 造成的早期通知問(wèn)題
多線(xiàn)程的實(shí)現(xiàn)方法
深入 Java 內(nèi)存模型(1)
多線(xiàn)程環(huán)境下安全使用集合 API
并發(fā)新特性—Lock 鎖與條件變量
生產(chǎn)者—消費(fèi)者模型
深入 Java 內(nèi)存模型(2)
線(xiàn)程中斷
Volatile 關(guān)鍵字(上)
并發(fā)新特性—阻塞隊(duì)列與阻塞棧
可重入內(nèi)置鎖
守護(hù)線(xiàn)程與線(xiàn)程阻塞
并發(fā)新特性—障礙器 CyclicBarrier
Volatile 關(guān)鍵字(下)
synchronized 關(guān)鍵字
synchronized 的另個(gè)一重要作用:內(nèi)存可見(jiàn)性
并發(fā)新特性—Executor 框架與線(xiàn)程池
并發(fā)性與多線(xiàn)程介紹
死鎖
實(shí)現(xiàn)內(nèi)存可見(jiàn)性的兩種方法比較:synchronized 和 Volatile
線(xiàn)程掛起、恢復(fù)與終止

synchronized 關(guān)鍵字

在并發(fā)編程中,多線(xiàn)程同時(shí)并發(fā)訪(fǎng)問(wèn)的資源叫做臨界資源,當(dāng)多個(gè)線(xiàn)程同時(shí)訪(fǎng)問(wèn)對(duì)象并要求操作相同資源時(shí),分割了原子操作就有可能出現(xiàn)數(shù)據(jù)的不一致或數(shù)據(jù)不完整的情況,為避免這種情況的發(fā)生,我們會(huì)采取同步機(jī)制,以確保在某一時(shí)刻,方法內(nèi)只允許有一個(gè)線(xiàn)程。

采用 synchronized 修飾符實(shí)現(xiàn)的同步機(jī)制叫做互斥鎖機(jī)制,它所獲得的鎖叫做互斥鎖。每個(gè)對(duì)象都有一個(gè) monitor (鎖標(biāo)記),當(dāng)線(xiàn)程擁有這個(gè)鎖標(biāo)記時(shí)才能訪(fǎng)問(wèn)這個(gè)資源,沒(méi)有鎖標(biāo)記便進(jìn)入鎖池。任何一個(gè)對(duì)象系統(tǒng)都會(huì)為其創(chuàng)建一個(gè)互斥鎖,這個(gè)鎖是為了分配給線(xiàn)程的,防止打斷原子操作。每個(gè)對(duì)象的鎖只能分配給一個(gè)線(xiàn)程,因此叫做互斥鎖。

這里就使用同步機(jī)制獲取互斥鎖的情況,進(jìn)行幾點(diǎn)說(shuō)明:

  1. 如果同一個(gè)方法內(nèi)同時(shí)有兩個(gè)或更多線(xiàn)程,則每個(gè)線(xiàn)程有自己的局部變量拷貝。

  2. 類(lèi)的每個(gè)實(shí)例都有自己的對(duì)象級(jí)別鎖。當(dāng)一個(gè)線(xiàn)程訪(fǎng)問(wèn)實(shí)例對(duì)象中的 synchronized 同步代碼塊或同步方法時(shí),該線(xiàn)程便獲取了該實(shí)例的對(duì)象級(jí)別鎖,其他線(xiàn)程這時(shí)如果要訪(fǎng)問(wèn) synchronized 同步代碼塊或同步方法,便需要阻塞等待,直到前面的線(xiàn)程從同步代碼塊或方法中退出,釋放掉了該對(duì)象級(jí)別鎖。

  3. 訪(fǎng)問(wèn)同一個(gè)類(lèi)的不同實(shí)例對(duì)象中的同步代碼塊,不存在阻塞等待獲取對(duì)象鎖的問(wèn)題,因?yàn)樗鼈儷@取的是各自實(shí)例的對(duì)象級(jí)別鎖,相互之間沒(méi)有影響。

  4. 持有一個(gè)對(duì)象級(jí)別鎖不會(huì)阻止該線(xiàn)程被交換出來(lái),也不會(huì)阻塞其他線(xiàn)程訪(fǎng)問(wèn)同一示例對(duì)象中的非 synchronized 代碼。當(dāng)一個(gè)線(xiàn)程 A 持有一個(gè)對(duì)象級(jí)別鎖(即進(jìn)入了 synchronized 修飾的代碼塊或方法中)時(shí),線(xiàn)程也有可能被交換出去,此時(shí)線(xiàn)程 B 有可能獲取執(zhí)行該對(duì)象中代碼的時(shí)間,但它只能執(zhí)行非同步代碼(沒(méi)有用 synchronized 修飾),當(dāng)執(zhí)行到同步代碼時(shí),便會(huì)被阻塞,此時(shí)可能線(xiàn)程規(guī)劃器又讓 A 線(xiàn)程運(yùn)行,A 線(xiàn)程繼續(xù)持有對(duì)象級(jí)別鎖,當(dāng) A 線(xiàn)程退出同步代碼時(shí)(即釋放了對(duì)象級(jí)別鎖),如果 B 線(xiàn)程此時(shí)再運(yùn)行,便會(huì)獲得該對(duì)象級(jí)別鎖,從而執(zhí)行 synchronized 中的代碼。

  5. 持有對(duì)象級(jí)別鎖的線(xiàn)程會(huì)讓其他線(xiàn)程阻塞在所有的 synchronized 代碼外。例如,在一個(gè)類(lèi)中有三個(gè)synchronized 方法 a,b,c,當(dāng)線(xiàn)程 A 正在執(zhí)行一個(gè)實(shí)例對(duì)象 M 中的方法 a 時(shí),它便獲得了該對(duì)象級(jí)別鎖,那么其他的線(xiàn)程在執(zhí)行同一實(shí)例對(duì)象(即對(duì)象 M)中的代碼時(shí),便會(huì)在所有的 synchronized 方法處阻塞,即在方法 a,b,c 處都要被阻塞,等線(xiàn)程 A 釋放掉對(duì)象級(jí)別鎖時(shí),其他的線(xiàn)程才可以去執(zhí)行方法 a,b 或者 c 中的代碼,從而獲得該對(duì)象級(jí)別鎖。

  6. 使用 synchronized(obj)同步語(yǔ)句塊,可以獲取指定對(duì)象上的對(duì)象級(jí)別鎖。obj 為對(duì)象的引用,如果獲取了 obj 對(duì)象上的對(duì)象級(jí)別鎖,在并發(fā)訪(fǎng)問(wèn) obj 對(duì)象時(shí)時(shí),便會(huì)在其 synchronized 代碼處阻塞等待,直到獲取到該 obj對(duì)象的對(duì)象級(jí)別鎖。當(dāng) obj 為 this 時(shí),便是獲取當(dāng)前對(duì)象的對(duì)象級(jí)別鎖。

  7. 類(lèi)級(jí)別鎖被特定類(lèi)的所有示例共享,它用于控制對(duì) static 成員變量以及 static 方法的并發(fā)訪(fǎng)問(wèn)。具體用法與對(duì)象級(jí)別鎖相似。

  8. 互斥是實(shí)現(xiàn)同步的一種手段,臨界區(qū)、互斥量和信號(hào)量都是主要的互斥實(shí)現(xiàn)方式。synchronized 關(guān)鍵字經(jīng)過(guò)編譯后,會(huì)在同步塊的前后分別形成 monitorenter 和 monitorexit 這兩個(gè)字節(jié)碼指令。根據(jù)虛擬機(jī)規(guī)范的要求,在執(zhí)行 monitorenter 指令時(shí),首先要嘗試獲取對(duì)象的鎖,如果獲得了鎖,把鎖的計(jì)數(shù)器加 1,相應(yīng)地,在執(zhí)行 monitorexit 指令時(shí)會(huì)將鎖計(jì)數(shù)器減 1,當(dāng)計(jì)數(shù)器為 0 時(shí),鎖便被釋放了。由于 synchronized 同步塊對(duì)同一個(gè)線(xiàn)程是可重入的,因此一個(gè)線(xiàn)程可以多次獲得同一個(gè)對(duì)象的互斥鎖,同樣,要釋放相應(yīng)次數(shù)的該互斥鎖,才能最終釋放掉該鎖。