synchronized、鎖、多線程同步的原理是咋樣的

先綜述個結論:

一般說的synchronized用來做多線程同步功能,其實synchronized只是提供多線程互斥,而對象的wait()和notify()方法才提供線程的同步功能。

一般說synchronized是加鎖,或者說是加對象鎖,其實對象鎖只是synchronized在實現鎖機制中的一種鎖(重量鎖,用這種方式互斥線程開銷大所以叫重量鎖,或者叫對象monitor),而synchronized的鎖機制會根據線程競爭情況在運行會有偏向鎖、輕量鎖、對象鎖,自旋鎖(或自適應自旋鎖)等,總之,synchronized可以認為是一個幾種鎖過程的封裝。


原理

通常說的synchronized在方法或塊上加鎖,這里的鎖就是對象鎖(當然也可以在類上面),或者叫重量鎖,在JVM中又叫對象監視器(Monitor),就是對象來監視線程的互斥。

先來回顧一下對象在堆里的邏輯結構:

對象在內存中的結構看這里》》

對象頭里的結構大致如此:

其中Tag的2bit用來顯示鎖類型。通常我們說synchronized的對象鎖,就是這里Tag=10時的monitor對象,這里的Monitor address就是這個monitor對象(就是重量鎖)的地址。

當多個線程同時請求synchronized方法或塊時,monitor會設置幾個虛擬邏輯數據結構來管理這些多線程。下圖是簡化了的管理結構。

新請求的線程會首先被加入到線程排隊隊列中,線程阻塞,當某個擁有鎖的線程unlock之后,則排隊隊列里的線程競爭上崗(synchronized是不公平競爭鎖,下面還會講到)。如果運行的線程調用對象的wait()后就釋放鎖并進入wait線程集合那邊,當調用對象的notify()或notifyall()后,wait線程就到排隊那邊。這是大致的邏輯。

同時再看看線程的狀態圖

Blocked就是阻塞狀態。

wait()和sleep()最大的不同在于wait()會釋放對象鎖,而sleep()不會!wait、sleep、yield區別如下:

似乎講到這里,synchronized鎖和wait()、notify()來實現多線程同步就完成了。

但是,自旋鎖或自適應自旋鎖:

因為線程阻塞后進入排隊隊列和喚醒都需要CPU從用戶態轉為核心態,尤其頻繁的阻塞和喚醒對CPU來說是負荷很重的工作。同時統計發現,很多對象鎖的鎖定狀態只會持續很短的一段時間,例如一個線程切換周期,這樣的話在很短的時間內阻塞線程又很快喚醒線程顯然不值得,所以引入了自旋鎖概念。

所謂“自旋”,就monitor并不把線程阻塞放入排隊隊列,而是去執行一個無意義的循環,循環結束后看看是否鎖已釋放并直接進行競爭上崗步驟,如果競爭不到繼續自旋循環,循環過程中線程的狀態一直處于running狀態。明顯自旋鎖使得synchronized的對象鎖方式在線程之間引入了不公平。但是這樣可以保證大吞吐率和執行效率。

不過雖然自旋鎖方式省去了阻塞線程的時間和空間(隊列的維護等)開銷,但是長時間自旋也是很低效的。所以自旋的次數一般控制在一個范圍內,例如10,50等,在超出這個范圍后,線程就進入排隊隊列。

自適應自旋鎖,就是自旋的次數是通過JVM在運行時收集的統計信息,動態調整自旋鎖的自旋次數上界。

講到這里似乎synchronized鎖的過程更加豐滿了。

不過synchronized在運行過程中不是一下子就到對象鎖這個級別的,它根據線程競爭情況會經過幾次升級變化。這里就出現了另外幾種鎖。

輕量鎖和偏向鎖

當多線程環境進入synchronized區域的線程沒競爭時,JVM并不會馬上創建對象鎖,而是用輕量鎖或偏向鎖。

不過需要明確的是,輕量鎖和偏向鎖,都不能代替重量鎖,只不過是在沒有多線程競爭時,沒必要用重量鎖而無畏的消耗資源。但是一旦出現了多線程競爭時,synchronized區域的輕量鎖或偏向鎖都會立即升級為重量鎖。

輕量鎖或偏向鎖使用的條件是進入synchronized區域時沒有其他任何其他線程在使用。

這時線程t訪問對象的synchronized區域時,對象頭的標志位Tag狀態為01,以及還有1位的偏向信息用于記錄這個對象是否可用偏向鎖。然后t在對象上申請輕量鎖時,若偏向信息為0,表明當前對象還未加鎖,或加過偏向鎖(加過,注意是加過偏向鎖的對象只能被同樣的線程加鎖,如果不同的線程想要獲取鎖,需要先將偏向鎖升級為輕量鎖,稍后會講到),在判斷對當前對象確實沒有被任何其他線程鎖住后,即可以在該對象上加輕量鎖。

加輕量鎖的過程很簡單:在當前線程的棧幀(stack?frame)中生成一個鎖記錄(lock?record),這個鎖記錄比前面說的那個對象鎖(管理線程隊列的monitor)簡單多了,它只是對象頭的一個拷貝。然后把對象頭里的tag改成00,并把這個棧幀里的lock?record地址放入對象頭里。若操作成功,那就完成了輕量鎖操作。如果不成功,說明有線程在競爭,則需要在當前對象上生成重量鎖來進行多線程同步,然后將Tag狀態改為10,并生成Monitor對象(重量鎖對象),對象頭里也會放入Monitor對象的地址。最后將當前線程t排隊隊列中。

輕量鎖的解鎖過程也很簡單就是把棧幀里剛才的那個lock?record拷貝到對象頭里,若替換成功,則解鎖完成,若替換不成功,表示在當前線程持有鎖的這段時間內,其他線程也競爭過鎖,并且發生了鎖升級為重量鎖,這時需要去Monitor的等待隊列中喚醒一個線程去重新競爭鎖。

偏向鎖是比輕量鎖還輕量的鎖機制。當synchronized區域長期都由同一個線程加鎖、解鎖時,jvm就用偏向鎖來做,它的加鎖解鎖比輕量鎖操作起來指令更加簡化。不過一旦有其他線程使用synchronized區域,即使沒有線程間競爭,也會把偏向鎖升級為輕量鎖,當然如果發生線程競爭就再升級為對象鎖。

鎖的公平與不公平:公平鎖是指線程獲得鎖的順序按照fifo的原則,先排隊的先得。非公平鎖指每個線程都先要競爭鎖,不管排隊先后,所以后到的線程有可能無需進入等待隊列直接競爭到鎖。非公平鎖雖然可能導致某些線程饑餓,但是鎖的吞吐率是公平鎖好幾倍,synchronized是一個典型的非公平鎖方案,而且沒法做成公平鎖。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,983評論 6 537
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,772評論 3 422
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,947評論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,201評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,960評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,350評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,406評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,549評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,104評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,914評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,089評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,647評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,340評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,753評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,007評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,834評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,106評論 2 375

推薦閱讀更多精彩內容