并發(fā)編程-鎖的優(yōu)化

上一篇 <<<鎖的深入化
下一篇 >>>Java內(nèi)存模型(JMM)


鎖的升級順序:無鎖狀態(tài)涕滋、偏向鎖狀態(tài)、輕量級鎖狀態(tài)纹笼、重量級鎖狀態(tài)拴签。
鎖可以從偏向鎖升級到重量級鎖孝常,是單向的,不會出現(xiàn)鎖的降級蚓哩。

用戶態(tài)和內(nèi)核態(tài)

內(nèi)核態(tài)(Kernel Mode):運行操作系統(tǒng)程序构灸,操作硬件 讀取io流、
用戶態(tài)(User Mode):運行用戶程序


偏向鎖

  • 定義:從始至終只有一個線程在請求鎖和釋放鎖
  • 偏向線程: 占用鎖的線程
  • 好處: 偏向鎖適合于只有一個線程重復(fù)獲取鎖的時候岸梨,沒有任何的競爭喜颁,從而提高鎖的效率稠氮。

原理/實現(xiàn)過程:
a、當獲取到鎖的時候
--對象頭的偏向模式設(shè)置為“1”半开、偏向鎖標志位設(shè)置01隔披,進入偏向模式。
--對象的棧楨中記錄偏向鎖的線程ID(也就是mark word中)
b寂拆、下次獲取鎖的時候奢米,判斷偏向鎖ID和當前線程一致,則直接進入代碼塊執(zhí)行漓库,減少CAS的操作恃慧,也就是減少CPU用戶態(tài)和內(nèi)核態(tài)的切換
--如果為0(表示線程還不是偏向鎖,是無鎖狀態(tài))渺蒿;采用CAS操作將偏向鎖字段設(shè)置為1痢士;并且更新自己的線程ID到mark word 字段中;
--如果為1且不是當前線程茂装,表示此時偏向鎖已經(jīng)被別的線程獲鹊□濉;則此時線程不斷嘗試使用CAS獲取偏向鎖少态;或者將偏向鎖撤銷城侧,升級成輕量級鎖; (升級概率較大)

如何開啟偏向鎖:
jdk5中默認關(guān)閉彼妻,jdk6之后默認開啟嫌佑,但在應(yīng)用程序啟動幾秒鐘之后才激活可以使用-XX:BiasedLockingStartupDelay=0參數(shù)關(guān)閉延遲
如果確定應(yīng)用程序中所有鎖通常情況下處于競爭狀態(tài),可以通過
-XX:-UseBiasedLocking=false參數(shù)關(guān)閉偏向鎖

偏向鎖撤銷場景:
a侨歉、有其他線程來競爭的時候才會釋放偏向鎖
b屋摇、偏向鎖的撤銷必須等待全局安全的點
c、將對象頭中的標記01恢復(fù)為00
d幽邓、hash計算

輕量級鎖

  • 應(yīng)用場景: 當多個線程在間隔的方式競爭我們的鎖對象炮温,短暫結(jié)合自旋控制。

鎖的獲取:
(1). 判斷當前對象是否處于無鎖狀態(tài)(hashcode牵舵、0柒啤、01),若是畸颅,則JVM首先將在當前線程的棧幀中建立一個名為鎖記錄(Lock Record)的空間担巩,用于存儲鎖對象目前的Mark Word的拷貝(官方把這份拷貝加了一個Displaced前綴,即Displaced Mark Word)没炒;否則執(zhí)行步驟(3)兵睛;
(2). JVM利用CAS操作嘗試將對象的Mark Word更新為指向Lock Record的指針,如果成功表示競爭到鎖,則將鎖標志位變成00(表示此對象處于輕量級鎖狀態(tài))祖很,執(zhí)行同步操作笛丙;如果失敗則執(zhí)行步驟(3);
(3). 判斷當前對象的Mark Word是否指向當前線程的棧幀假颇,如果是則表示當前線程已經(jīng)持有當前對象的鎖胚鸯,則直接執(zhí)行同步代碼塊;否則只能說明該鎖對象已經(jīng)被其他線程搶占了笨鸡,這時輕量級鎖需要膨脹為重量級鎖姜钳,鎖標志位變成10,后面等待的線程將會進入阻塞狀態(tài)形耗;

鎖的釋放
(1). 取出在獲取輕量級鎖保存在Displaced Mark Word中的數(shù)據(jù)哥桥;
(2). 用CAS操作將取出的數(shù)據(jù)替換當前對象的Mark Word中,如果成功激涤,則說明釋放鎖成功拟糕,否則執(zhí)行(3);
(3). 如果CAS操作替換失敗倦踢,說明有其他線程嘗試獲取該鎖送滞,則需要在釋放鎖的同時需要喚醒被掛起的線程。

重量級鎖

沒有獲取到鎖的線程會變?yōu)樽枞臓顟B(tài)辱挥,效率極低
線程的競爭不會使用自旋犁嗅,不會消耗cpu資源,適合于同步代碼執(zhí)行比較長的時間晤碘。

偏向鎖褂微、輕量級鎖和重量級鎖區(qū)別與轉(zhuǎn)換

a.偏向鎖:加鎖和解鎖不需要額外的開銷,只適合于同一個線程訪問同步代碼塊园爷,如果多個線程同時競爭的時候宠蚂,會撤銷該鎖。
b.輕量級鎖:競爭的線程不會阻塞腮介,提高了程序響應(yīng)速度,如果始終得不到鎖的競爭線程端衰,則使用自旋的形式叠洗,消耗cpu資源,適合于同步代碼塊執(zhí)行非陈枚快的情況下灭抑。
c.重量級鎖: 線程的競爭不會使用自旋,不會消耗cpu資源抵代,適合于同步代碼執(zhí)行比較長的時間腾节。


鎖之間的轉(zhuǎn)換
優(yōu)點 缺點 適用場景
偏向鎖 加鎖和解鎖不需要額外的消耗,和執(zhí)行非同步方法比僅存在納秒級的差距 如果線程之間存在競爭,會帶來額外的鎖撤銷的消耗 適用于只有一個線程訪問同步塊場景
輕量級鎖 競爭的線程不會阻塞案腺,提高了程序的響應(yīng)速度 如果始終得不到鎖競爭的線程使用自旋會消耗CPU 追求響應(yīng)時間庆冕,同步塊執(zhí)行速度非常快
重量級鎖 線程競爭不使用自旋劈榨,不會消耗CPU 線程阻塞访递,響應(yīng)時間緩慢 追求吞吐量,同步塊執(zhí)行速度較長

總結(jié)一下同辣,其實無鎖->偏向鎖->輕量級鎖->重量級鎖的轉(zhuǎn)化過程中沒那么復(fù)雜拷姿,注意記住:
(1)只有一個線程獲取鎖時旱函,就是偏向鎖响巢。
(2)多個線程時,不存在競爭(多個線程順序執(zhí)行)棒妨,輕量級鎖踪古。
(3)多個線程存在競爭時重量級鎖。

代碼示例

64位虛擬機mark word圖示
[markOop.hpp文件]
enum {  locked_value             = 0, // 0 00 輕量級鎖
         unlocked_value           = 1,// 0 01 無鎖
         monitor_value            = 2,// 0 10 重量級鎖
         marked_value             = 3,// 0 11 gc標志
         biased_lock_pattern      = 5 // 1 01 偏向鎖
  };



tips:對象的布局情況請參考Java基礎(chǔ)-對象布局

鎖的消除

鎖削除是指虛擬機即時編譯器在運行時靶衍,對一些代碼上要求同步灾炭,但是被檢測到不可能存在共享數(shù)據(jù)競爭的鎖進行削除。鎖削除的主要判定依據(jù)來源于逃逸分析的數(shù)據(jù)支持颅眶,如果判斷到一段代碼中蜈出,在堆上的所有數(shù)據(jù)都不會逃逸出去被其他線程訪問到,那就可以把它們當作棧上數(shù)據(jù)對待涛酗,認為它們是線程私有的铡原,同步加鎖自然就無須進行。

/**
 * StringBuffer的append方法每個都含有synchronized關(guān)鍵字商叹,而且都是this鎖
 * 每個線程都有自己獨立鎖燕刻,等于是沒鎖
 * @param args
 */
public static void main(String[] args) {
    andString("jarye", "xiaowang", "xiaohong");
}

public static String andString(String s1, String s2, String s3) {
    return new StringBuffer().append(s1).append(s2).append(s3).toString();
}

鎖的粗化/合并

通常情況下,為了保證多線程間的有效并發(fā)剖笙,會要求每個線程持有鎖的時間盡可能短卵洗,但是大某些情況下,一個程序?qū)ν粋€鎖不間斷弥咪、高頻地請求过蹂、同步與釋放,會消耗掉一定的系統(tǒng)資源聚至,因為鎖的講求酷勺、同步與釋放本身會帶來性能損耗,這樣高頻的鎖請求就反而不利于系統(tǒng)性能的優(yōu)化了扳躬,雖然單次同步操作的時間可能很短脆诉。
鎖粗化就是告訴我們?nèi)魏问虑槎加袀€度甚亭,有些情況下我們反而希望把很多次鎖的請求合并成一個請求,以降低短時間內(nèi)大量鎖請求击胜、同步亏狰、釋放帶來的性能損耗。

/**
 * StringBuffer的append方法每個都含有synchronized關(guān)鍵字
 * 在執(zhí)行的時候潜的,會合并在for之前加鎖骚揍,之后釋放鎖
 * @param args
 */
public static void main(String[] args) {
    StringBuffer sf = new StringBuffer();
    for(int i=0;i<10;i++){
        sf.append(i);
    }
}

Synchronized優(yōu)化方案

a.減少Synchronized同步的范圍,只會使用偏向鎖或者輕量鎖
b.類似Conhashmap底層實現(xiàn)分段鎖原理 降低鎖的粒度
c.鎖一定要做做讀寫分離


相關(guān)文章鏈接:
<<<多線程基礎(chǔ)
<<<線程安全與解決方案
<<<鎖的深入化
<<<Java內(nèi)存模型(JMM)
<<<Volatile解決JMM的可見性問題
<<<Volatile的偽共享和重排序
<<<CAS無鎖模式及ABA問題
<<<Synchronized鎖
<<<Lock鎖
<<<AQS同步器
<<<Condition
<<<CountDownLatch同步計數(shù)器
<<<Semaphore信號量
<<<CyclicBarrier屏障
<<<線程池
<<<并發(fā)隊列
<<<Callable與Future模式
<<<Fork/Join框架
<<<Threadlocal
<<<Disruptor框架
<<<如何優(yōu)化多線程總結(jié)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末啰挪,一起剝皮案震驚了整個濱河市信不,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌亡呵,老刑警劉巖抽活,帶你破解...
    沈念sama閱讀 212,454評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異锰什,居然都是意外死亡下硕,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評論 3 385
  • 文/潘曉璐 我一進店門汁胆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來梭姓,“玉大人,你說我怎么就攤上這事嫩码∮猓” “怎么了?”我有些...
    開封第一講書人閱讀 157,921評論 0 348
  • 文/不壞的土叔 我叫張陵铸题,是天一觀的道長铡恕。 經(jīng)常有香客問我,道長丢间,這世上最難降的妖魔是什么探熔? 我笑而不...
    開封第一講書人閱讀 56,648評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮烘挫,結(jié)果婚禮上诀艰,老公的妹妹穿的比我還像新娘。我一直安慰自己饮六,他們只是感情好其垄,可當我...
    茶點故事閱讀 65,770評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著喜滨,像睡著了一般捉捅。 火紅的嫁衣襯著肌膚如雪撤防。 梳的紋絲不亂的頭發(fā)上虽风,一...
    開封第一講書人閱讀 49,950評論 1 291
  • 那天棒口,我揣著相機與錄音,去河邊找鬼辜膝。 笑死无牵,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的厂抖。 我是一名探鬼主播茎毁,決...
    沈念sama閱讀 39,090評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼忱辅!你這毒婦竟也來了七蜘?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,817評論 0 268
  • 序言:老撾萬榮一對情侶失蹤墙懂,失蹤者是張志新(化名)和其女友劉穎橡卤,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體损搬,經(jīng)...
    沈念sama閱讀 44,275評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡碧库,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,592評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了巧勤。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片嵌灰。...
    茶點故事閱讀 38,724評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖颅悉,靈堂內(nèi)的尸體忽然破棺而出沽瞭,到底是詐尸還是另有隱情,我是刑警寧澤签舞,帶...
    沈念sama閱讀 34,409評論 4 333
  • 正文 年R本政府宣布秕脓,位于F島的核電站,受9級特大地震影響儒搭,放射性物質(zhì)發(fā)生泄漏吠架。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,052評論 3 316
  • 文/蒙蒙 一搂鲫、第九天 我趴在偏房一處隱蔽的房頂上張望傍药。 院中可真熱鬧,春花似錦魂仍、人聲如沸拐辽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽俱诸。三九已至,卻和暖如春赊舶,著一層夾襖步出監(jiān)牢的瞬間睁搭,已是汗流浹背赶诊。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留园骆,地道東北人舔痪。 一個月前我還...
    沈念sama閱讀 46,503評論 2 361
  • 正文 我出身青樓,卻偏偏與公主長得像锌唾,于是被迫代替她去往敵國和親锄码。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,627評論 2 350

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