二十三、“鎖”(四)synchronized 和 Lock

1催享、synchronized 和 Lock 孰優(yōu)孰劣杭隙,如何選擇?

相同點(diǎn)

synchronized 和 Lock 的相同點(diǎn)非常多因妙,重點(diǎn)講解 3 個(gè)比較大的相同點(diǎn)痰憎。
1)synchronized 和 Lock 都是用來(lái)保護(hù)資源線程安全的。
2)都可以保證可見(jiàn)性攀涵。
對(duì)于 synchronized 而言铣耘,線程 A 在進(jìn)入 synchronized 塊之前或在 synchronized 塊內(nèi)進(jìn)行操作,對(duì)于后續(xù)的獲得同一個(gè) monitor 鎖的線程 B 是可見(jiàn)的以故,也就是線程 B 是可以看到線程 A 之前的操作的蜗细,這也體現(xiàn)了 happens-before 針對(duì) synchronized 的一個(gè)原則。

而對(duì)于 Lock 而言怒详,它和 synchronized 是一樣炉媒,都可以保證可見(jiàn)性,如圖所示昆烁,在解鎖之前的所有操作對(duì)加鎖之后的所有操作都是可見(jiàn)的吊骤。

3)synchronized 和 ReentrantLock 都擁有可重入的特點(diǎn)。
這里的 ReentrantLock 是 Lock 接口的一個(gè)最主要的實(shí)現(xiàn)類(lèi)静尼,在對(duì)比 synchronized 和 Lock 的時(shí)候白粉,也會(huì)選擇 Lock 的主要實(shí)現(xiàn)類(lèi)來(lái)進(jìn)行對(duì)比∶├桑可重入指的是某個(gè)線程如果已經(jīng)獲得了一個(gè)鎖蜗元,現(xiàn)在試圖再次請(qǐng)求這個(gè)它已經(jīng)獲得的鎖或渤,如果它無(wú)需提前釋放這個(gè)鎖系冗,而是直接可以繼續(xù)使用持有的這個(gè)鎖,那么就是可重入的薪鹦。如果必須釋放鎖后才能再次申請(qǐng)這個(gè)鎖掌敬,就是不可重入的。

不同點(diǎn)

synchronized 和 Lock 的不同點(diǎn)非常多池磁,重點(diǎn)講解 7 個(gè)比較大的不同點(diǎn)奔害。
1)用法區(qū)別
synchronized 關(guān)鍵字可以加在方法上,不需要指定鎖對(duì)象(此時(shí)的鎖對(duì)象為 this)地熄,也可以新建一個(gè)同步代碼塊并且自定義 monitor 鎖對(duì)象华临;而 Lock 接口必須顯示用 Lock 鎖對(duì)象開(kāi)始加鎖 lock() 和解鎖 unlock(),并且一般會(huì)在 finally 塊中確保用 unlock() 來(lái)解鎖端考,以防發(fā)生死鎖雅潭。

與 Lock 顯式的加鎖和解鎖不同的是 synchronized 的加解鎖是隱式的揭厚,尤其是拋異常的時(shí)候也能保證釋放鎖,但是 Java 代碼中并沒(méi)有相關(guān)的體現(xiàn)扶供。

2)加解鎖順序不同
對(duì)于 Lock 而言如果有多把 Lock 鎖筛圆,Lock 可以不完全按照加鎖的反序解鎖,比如我們可以先獲取 Lock1 鎖椿浓,再獲取 Lock2 鎖太援,解鎖時(shí)則先解鎖 Lock1,再解鎖 Lock2扳碍,加解鎖有一定的靈活度提岔,如代碼所示。

lock1.lock();
lock2.lock();
...
lock1.unlock();
lock2.unlock();

但是 synchronized 無(wú)法做到笋敞,synchronized 解鎖的順序和加鎖的順序必須完全相反唧垦,例如:

synchronized(obj1){
    synchronized(obj2){
        ...
    }
}

那么在這里,順序就是先對(duì) obj1 加鎖液样,然后對(duì) obj2 加鎖振亮,然后對(duì) obj2 解鎖,最后解鎖 obj1鞭莽。這是因?yàn)?synchronized 加解鎖是由 JVM 實(shí)現(xiàn)的坊秸,在執(zhí)行完 synchronized 塊后會(huì)自動(dòng)解鎖,所以會(huì)按照 synchronized 的嵌套順序加解鎖澎怒,不能自行控制褒搔。

3)synchronized 鎖不夠靈活
一旦 synchronized 鎖已經(jīng)被某個(gè)線程獲得了,此時(shí)其他線程如果還想獲得喷面,那它只能被阻塞星瘾,直到持有鎖的線程運(yùn)行完畢或者發(fā)生異常從而釋放這個(gè)鎖。如果持有鎖的線程持有很長(zhǎng)時(shí)間才釋放惧辈,那么整個(gè)程序的運(yùn)行效率就會(huì)降低琳状,而且如果持有鎖的線程永遠(yuǎn)不釋放鎖,那么嘗試獲取鎖的線程只能永遠(yuǎn)等下去盒齿。

相比之下念逞,Lock 類(lèi)在等鎖的過(guò)程中,如果使用的是 lockInterruptibly 方法边翁,那么如果覺(jué)得等待的時(shí)間太長(zhǎng)了不想再繼續(xù)等待翎承,可以中斷退出,也可以用 tryLock() 等方法嘗試獲取鎖符匾,如果獲取不到鎖也可以做別的事叨咖,更加靈活。

4)synchronized 鎖只能同時(shí)被一個(gè)線程擁有,但是 Lock 鎖沒(méi)有這個(gè)限制甸各。
例如在讀寫(xiě)鎖中的讀鎖仰剿,可以同時(shí)被多個(gè)線程持有。

5)原理區(qū)別
synchronized 是內(nèi)置鎖痴晦,由 JVM 實(shí)現(xiàn)獲取鎖和釋放鎖的原理南吮,還分為偏向鎖、輕量級(jí)鎖誊酌、重量級(jí)鎖部凑。
Lock 根據(jù)實(shí)現(xiàn)不同,有不同的原理碧浊,例如 ReentrantLock 內(nèi)部是通過(guò) AQS 來(lái)獲取和釋放鎖的涂邀。

6)是否可以設(shè)置公平/非公平
公平鎖是指多個(gè)線程在等待同一個(gè)鎖時(shí),根據(jù)先來(lái)后到的原則依次獲得鎖箱锐。ReentrantLock 等 Lock 實(shí)現(xiàn)類(lèi)可以根據(jù)自己的需要來(lái)設(shè)置公平或非公平比勉,synchronized 則不能設(shè)置。

7)性能區(qū)別
在 Java 5 以及之前驹止,synchronized 的性能比較低浩聋,但是到了 Java 6 以后,發(fā)生了變化臊恋,因?yàn)?JDK 對(duì) synchronized 進(jìn)行了很多優(yōu)化衣洁,比如自適應(yīng)自旋、鎖消除抖仅、鎖粗化坊夫、輕量級(jí)鎖、偏向鎖等撤卢,所以后期的 Java 版本里的 synchronized 的性能并不比 Lock 差环凿。

如何選擇

1)如果能不用最好既不使用 Lock 也不使用 synchronized。因?yàn)樵谠S多情況下可以使用 java.util.concurrent 包中的機(jī)制放吩,它會(huì)為你處理所有的加鎖和解鎖操作智听,也就是推薦優(yōu)先使用工具類(lèi)來(lái)加解鎖。
2)如果 synchronized 關(guān)鍵字適合程序屎慢, 那么盡量使用它瞭稼,這樣可以減少編寫(xiě)代碼的數(shù)量,減少出錯(cuò)的概率腻惠。因?yàn)橐坏┩浽?finally 里 unlock,代碼可能會(huì)出很大的問(wèn)題欲虚,而使用 synchronized 更安全集灌。
3)如果特別需要 Lock 的特殊功能,比如嘗試獲取鎖、可中斷欣喧、超時(shí)功能等腌零,才使用 Lock。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末唆阿,一起剝皮案震驚了整個(gè)濱河市益涧,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌驯鳖,老刑警劉巖闲询,帶你破解...
    沈念sama閱讀 222,104評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異浅辙,居然都是意外死亡扭弧,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)记舆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)鸽捻,“玉大人,你說(shuō)我怎么就攤上這事泽腮∮眩” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,697評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵诊赊,是天一觀的道長(zhǎng)删咱。 經(jīng)常有香客問(wèn)我,道長(zhǎng)豪筝,這世上最難降的妖魔是什么痰滋? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,836評(píng)論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮续崖,結(jié)果婚禮上敲街,老公的妹妹穿的比我還像新娘。我一直安慰自己严望,他們只是感情好多艇,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著像吻,像睡著了一般峻黍。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上拨匆,一...
    開(kāi)封第一講書(shū)人閱讀 52,441評(píng)論 1 310
  • 那天姆涩,我揣著相機(jī)與錄音,去河邊找鬼惭每。 笑死骨饿,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播宏赘,決...
    沈念sama閱讀 40,992評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼绒北,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了察署?” 一聲冷哼從身側(cè)響起闷游,我...
    開(kāi)封第一講書(shū)人閱讀 39,899評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎贴汪,沒(méi)想到半個(gè)月后脐往,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,457評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡嘶是,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評(píng)論 3 341
  • 正文 我和宋清朗相戀三年钙勃,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片聂喇。...
    茶點(diǎn)故事閱讀 40,664評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡辖源,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出希太,到底是詐尸還是另有隱情克饶,我是刑警寧澤,帶...
    沈念sama閱讀 36,346評(píng)論 5 350
  • 正文 年R本政府宣布誊辉,位于F島的核電站矾湃,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏堕澄。R本人自食惡果不足惜邀跃,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評(píng)論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蛙紫。 院中可真熱鬧拍屑,春花似錦、人聲如沸坑傅。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,511評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)唁毒。三九已至蒜茴,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間浆西,已是汗流浹背粉私。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,611評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留室谚,地道東北人毡鉴。 一個(gè)月前我還...
    沈念sama閱讀 49,081評(píng)論 3 377
  • 正文 我出身青樓崔泵,卻偏偏與公主長(zhǎng)得像秒赤,于是被迫代替她去往敵國(guó)和親猪瞬。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評(píng)論 2 359