Synchronized 中的 4 個優(yōu)化祈纯,你知道幾個?

synchronized 在 JDK 1.5 時(shí)性能是比較低的叼耙,然而在后續(xù)的版本中經(jīng)過各種優(yōu)化迭代腕窥,它的性能也得到了前所未有的提升,之前說到過鎖膨脹對 synchronized 性能的提升筛婉,然而它也只是“眾多” synchronized 性能優(yōu)化方案中的一種簇爆,那么我們本文就來盤點(diǎn)一下 synchronized 的核心優(yōu)化方案。

synchronized 核心優(yōu)化方案主要包含以下 4 個:

  1. 鎖膨脹
  2. 鎖消除
  3. 鎖粗化
  4. 自適應(yīng)自旋鎖
image.png

1.鎖膨脹

我們先來回顧一下鎖膨脹對 synchronized 性能的影響爽撒,所謂的鎖膨脹是指 synchronized 從無鎖升級到偏向鎖入蛆,再到輕量級鎖,最后到重量級鎖的過程硕勿,它叫做鎖膨脹也叫做鎖升級哨毁。

image.png

JDK 1.6 之前,synchronized 是重量級鎖源武,也就是說 synchronized 在釋放和獲取鎖時(shí)都會從用戶態(tài)轉(zhuǎn)換成內(nèi)核態(tài)扼褪,而轉(zhuǎn)換的效率是比較低的。但有了鎖膨脹機(jī)制之后粱栖,synchronized 的狀態(tài)就多了無鎖话浇、偏向鎖以及輕量級鎖了,這時(shí)候在進(jìn)行并發(fā)操作時(shí)闹究,大部分的場景都不需要用戶態(tài)到內(nèi)核態(tài)的轉(zhuǎn)換了幔崖,這樣就大幅的提升了 synchronized 的性能。

2.鎖消除

很多人都了解 synchronized 中鎖膨脹的機(jī)制,但對接下來的 3 項(xiàng)優(yōu)化卻知之甚少岖瑰,這樣會在面試中錯失良機(jī)叛买,那么我們本文就把這 3 項(xiàng)優(yōu)化單獨(dú)拎出來講一下吧砂代。

鎖消除指的是在某些情況下蹋订,JVM 虛擬機(jī)如果檢測不到某段代碼被共享和競爭的可能性,就會將這段代碼所屬的同步鎖消除掉刻伊,從而<typo id="typo-672" data-origin="到底" ignoretag="true">到底</typo>提高程序性能的目的露戒。

鎖消除的依據(jù)是逃逸分析的數(shù)據(jù)支持,如 StringBuffer 的 append() 方法捶箱,或 Vector 的 add() 方法智什,在很多情況下是可以進(jìn)行鎖消除的,比如以下這段代碼:

public String method() {
    StringBuffer sb = new StringBuffer();
    for (int i = 0; i < 10; i++) {
        sb.append("i:" + i);
    }
    return sb.toString();
}

以上代碼經(jīng)過編譯之后的字節(jié)碼如下:

image.png

從上述結(jié)果可以看出丁屎,之前我們寫的線程安全的加鎖的 StringBuffer 對象荠锭,在生成字節(jié)碼之后就被替換成了不加鎖不安全的 StringBuilder 對象了,原因是 StringBuffer 的變量屬于一個局部變量晨川,并且不會從該方法中逃逸出去证九,所以此時(shí)我們就可以使用鎖消除(不加鎖)來加速程序的運(yùn)行。

3.鎖粗化

鎖粗化是指共虑,將多個連續(xù)的加鎖愧怜、解鎖操作連接在一起,擴(kuò)展成一個范圍更大的鎖妈拌。

我只聽說鎖“細(xì)化”可以提高程序的執(zhí)行效率拥坛,也就是將鎖的范圍盡可能縮小,這樣在鎖競爭時(shí)尘分,等待獲取鎖的線程才能更早<typo id="typo-1221" data-origin="的" ignoretag="true">的</typo>獲取鎖猜惋,從而提高程序的運(yùn)行效率,但鎖粗化是如何提高性能的呢培愁?

沒錯惨奕,鎖細(xì)化的觀點(diǎn)在大多數(shù)情況下都是成立了,但是一系列連續(xù)加鎖和解鎖的操作竭钝,也會導(dǎo)致不必要的性能開銷梨撞,從而影響程序的執(zhí)行效率,比如這段代碼:

public String method() {
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < 10; i++) {
        // 偽代碼:加鎖操作
        sb.append("i:" + i);
        // 偽代碼:解鎖操作
    }
    return sb.toString();
}

這里我們不考慮編譯器優(yōu)化的情況香罐,如果在 for 循環(huán)中定義鎖卧波,那么鎖的范圍很小,但每次 for 循環(huán)都需要進(jìn)行加鎖和釋放鎖的操作庇茫,性能是很低的港粱;但如果我們直接在 for 循環(huán)的外層加一把鎖,那么對于同一個對象操作這段代碼的性能就會提高很多,如下偽代碼所示:

public String method() {
    StringBuilder sb = new StringBuilder();
    // 偽代碼:加鎖操作
    for (int i = 0; i < 10; i++) {
        sb.append("i:" + i);
    }
    // 偽代碼:解鎖操作
    return sb.toString();
}

鎖粗化的作用:如果檢測到同一個對象執(zhí)行了連續(xù)的加鎖和解鎖的操作查坪,則會將這一系列操作合并成一個更大的鎖寸宏,從而提升程序的執(zhí)行效率

4.自適應(yīng)自旋鎖

自旋鎖是指通過自身循環(huán)偿曙,嘗試獲取鎖的一種方式氮凝,偽代碼實(shí)現(xiàn)如下:

// 嘗試獲取鎖
while(!isLock()){

}

自旋鎖優(yōu)點(diǎn)在于它避免一些線程的掛起和恢復(fù)操作,因?yàn)閽炱鹁€程和恢復(fù)線程都需要從用戶態(tài)轉(zhuǎn)入內(nèi)核態(tài)望忆,這個過程是比較慢的罩阵,所以通過自旋的方式可以一定程度上避免線程掛起和恢復(fù)所造成的性能開銷

但是启摄,如果長時(shí)間自旋還獲取不到鎖稿壁,那么也會造成一定的資源浪費(fèi),所以我們通常會給自旋設(shè)置一個固定的值來避免一直自旋的性能開銷歉备。然而對于 synchronized 關(guān)鍵字來說傅是,它的自旋鎖更加的“智能”,synchronized 中的自旋鎖是自適應(yīng)自旋鎖蕾羊,這就好比之前一直開的手動擋的三輪車喧笔,而經(jīng)過了 JDK 1.6 的優(yōu)化之后,我們的這部“車”,一下子變成自動擋的蘭博基尼了。

image.png

自適應(yīng)自旋鎖是指陶舞,線程自旋的次數(shù)不再是固定的值缀雳,而是一個動態(tài)改變的值,這個值會根據(jù)前一次自旋獲取鎖的狀態(tài)來決定此次自旋的次數(shù)。比如上一次通過自旋成功獲取到了鎖,那么這次通過自旋也有可能會獲取到鎖,所以這次自旋的次數(shù)就會增多一些梳侨,而如果上一次通過自旋沒有成功獲取到鎖,那么這次自旋可能也獲取不到鎖日丹,所以為了避免資源的浪費(fèi)走哺,就會少循環(huán)或者不循環(huán),以提高程序的執(zhí)行效率哲虾。簡單來說丙躏,如果線程自旋成功了,則下次自旋的次數(shù)會增多束凑,如果失敗晒旅,下次自旋的次數(shù)會減少。

總結(jié)

本文我們介紹了 4 種優(yōu)化 synchronized 的方案汪诉,其中鎖膨脹和自適應(yīng)自旋鎖是 synchronized 關(guān)鍵字自身的優(yōu)化實(shí)現(xiàn)废恋,而鎖消除和鎖粗化是 JVM 虛擬機(jī)對 synchronized 提供的優(yōu)化方案,這些優(yōu)化方案最終使得 synchronized 的性能得到了大幅的提升,也讓它在并發(fā)編程中占據(jù)了一席之地鱼鼓。

作者:Java中文社群
原文鏈接:https://juejin.cn/post/6994443415911923719

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末拟烫,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子迄本,更是在濱河造成了極大的恐慌硕淑,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件岸梨,死亡現(xiàn)場離奇詭異喜颁,居然都是意外死亡稠氮,警方通過查閱死者的電腦和手機(jī)曹阔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來隔披,“玉大人赃份,你說我怎么就攤上這事∩菝祝” “怎么了抓韩?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長鬓长。 經(jīng)常有香客問我谒拴,道長,這世上最難降的妖魔是什么涉波? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任英上,我火速辦了婚禮,結(jié)果婚禮上啤覆,老公的妹妹穿的比我還像新娘苍日。我一直安慰自己,他們只是感情好窗声,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布相恃。 她就那樣靜靜地躺著,像睡著了一般笨觅。 火紅的嫁衣襯著肌膚如雪拦耐。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天见剩,我揣著相機(jī)與錄音杀糯,去河邊找鬼。 笑死炮温,一個胖子當(dāng)著我的面吹牛火脉,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼倦挂,長吁一口氣:“原來是場噩夢啊……” “哼畸颅!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起方援,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤没炒,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后犯戏,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體送火,經(jīng)...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年先匪,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了种吸。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,137評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡呀非,死狀恐怖坚俗,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情岸裙,我是刑警寧澤猖败,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站降允,受9級特大地震影響恩闻,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜剧董,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一幢尚、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧送滞,春花似錦侠草、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至褂微,卻和暖如春功蜓,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背宠蚂。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工式撼, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人求厕。 一個月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓著隆,卻偏偏與公主長得像扰楼,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子美浦,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,086評論 2 355

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