多執行緒 Synchronized的優化

2021-10-04 23:10:22 字數 2379 閱讀 1035

對synchronized不太了解的同學,可以先參考我的另外一篇文章【多執行緒】淺說synchronized

在早期版本中,synchronized是一種重量級鎖,其底層由monitor實現,而monitor又依賴於作業系統的mutex lock。執行緒獲取到鎖後,需要切換狀態,而作業系統在實現執行緒的切換時,需要從使用者態轉為核心態,這是乙個非常耗時,非常重的操作。因此在之前,synchronized是一種重量級鎖。

現在的synchronized已經沒有之前那麼笨重了,在虛擬機器層面,對synchronized做了較大的優化,引入了自旋鎖、適應性自旋鎖、鎖消除、鎖粗化,可以減少鎖操作的開銷。

自旋鎖

有時候,獲取到鎖的執行緒執行的操作耗時極短,為了這麼點微不足道的時間,將接下來等待鎖的執行緒掛起非常的不值得。掛起執行緒的操作需要在核心態完成,從使用者態切換到核心態,耗時比較嚴重。

因此現在增加這麼一樣操作,讓等待鎖的執行緒執行忙迴圈等待,不停地去嘗試獲取鎖,像一種自旋的操作,故稱之為自旋鎖

如果之前執行緒占有鎖的時間極短,那麼自旋鎖的效能將非常的好。但若是占有鎖的時間較長,那麼自旋鎖將白白消耗cpu的資源,在自旋次數到了之後,將會被掛起。

在jdk1.4的時候,自旋鎖預設關閉;jdk1.6之後,自旋鎖預設開啟,預設自旋10次,當然也可以使用preblockspin來修改自旋次數

自旋鎖的痛點在於:無法在不同場景中,確定出乙個可靠的自旋次數。因此,衍生出來適應性自旋鎖。

適應性自旋鎖

在適應性自旋鎖中,自旋的次數不再固定,一般由之前自旋的次數和鎖持有者的狀態決定

如果在乙個鎖物件上,之前的執行緒都能通過自旋來獲取到鎖,並且沒有超過自旋次數,那麼虛擬機器認為,通過自旋獲取到鎖的概率很大,下一次會增加自旋的次數。相反的,如果之前很少有執行緒通過自旋獲取到鎖,那麼虛擬機會減少自旋的次數,減少到一定次數後,甚至會直接放棄自旋,公升級為重量級鎖。

可以看出,適應性自旋鎖十分機智。

鎖消除

從字面意思上可以看出,這是一種直接去除鎖的方法,簡單粗暴。

對於那些根本不可能存在鎖競爭卻又包含鎖的情況,虛擬機會直接消除這個鎖,避免無意義的鎖請求。比如我在純單執行緒中對某個方法或者變數加鎖,或者呼叫內部實現有鎖的物件(vector、stringbuffer與hashtable等),虛擬機會直接消除毫無意義的加鎖。

鎖粗化

在上一文中【多執行緒】淺說synchronized,我們談到了synchronized的應用-雙重檢驗鎖的優化過程,強調將加鎖的範圍盡量限制得小一些,直到存在鎖競爭的實際區域才加鎖,這樣程式執行更加高效。

但是,如果存在這樣的一種情況:反覆的對同乙個物件執行加鎖解鎖的操作,也會導致cpu資源的過度消耗

鎖粗化,就是將反覆的加鎖操作粗化成乙個範圍更大的鎖,這樣加鎖只有一次。

鎖的狀態有以下幾種:

無鎖狀態

偏向鎖狀態

輕量級鎖狀態

重量級鎖狀態

其中,無鎖狀態對應於鎖消除,monitor對應於重量級鎖,也就是1.6之前的synchronized。

偏向鎖

偏向鎖的核心要義就體現在「偏」字上,這個鎖偏向第乙個獲取到它的執行緒。

在大部分情況下,不存在激烈的鎖競爭,總是由同乙個執行緒獲取到該鎖。那麼為了減少同乙個執行緒獲取鎖帶來的開銷,就引入了偏向鎖。

如果乙個執行緒不斷的獲取到了鎖,那麼該鎖就進入偏向鎖狀態。當這個執行緒再次請求鎖時,無需做任何同步操作,直接獲取到鎖。

當然,偏向鎖適用於基本無鎖競爭的情況,當鎖競爭激烈時,偏向鎖就失去了作用,會公升級為輕量級鎖。

輕量級鎖

在偏向鎖的狀態下,此時又出現了乙個執行緒,與偏向執行緒競爭該鎖,此時該鎖會公升級為輕量級鎖。

舉個例子,比如建立乙個執行緒1執行同步print()方法列印奇數,這時候的鎖狀態為偏向鎖。此時,再建立乙個執行緒2同樣執行同步print()方法列印偶數,偏向鎖就會公升級為輕量級鎖。執行緒1列印某個奇數時,執行緒2並沒有被掛起,而是處於一種自旋狀態,這種自旋效率很高。可是,當我再建立100個執行緒時,同樣執行同步print()方法,自旋的效率將會變得十分低下,此時輕量級鎖會公升級為重量級鎖,即使用monitor來進行同步。

鎖的公升級

無鎖、偏向鎖、輕量級鎖與重量級鎖,會隨著鎖競爭的公升級而公升級。

從一開始的偏向鎖,產生鎖競爭後,公升級為輕量級鎖,自旋失敗後,公升級為重量級鎖,一般來說,鎖的公升級是單向的。

多執行緒之Synchronized

作用 阻塞執行緒,保證同一時刻最多只有1個執行緒執行。原理 依賴 jvm 實現同步,底層通過乙個監視器物件 monitor 完成,wait notify 等方法也依賴於 monitor 物件。使用 synchronized 修飾 塊 類的例項方法 靜態方法 synchronized同步鎖的型別 物件...

多執行緒 執行緒互斥之synchronized 詳解

定義 執行緒互斥是指某一資源同時只允許乙個訪問者對其進行訪問,具有唯一性和排它性。但互斥無法限制訪問者對資源的訪問順序,即訪問是無序的。我們都知道保證執行緒完整執行。則需要對其加鎖。使用synchronized關鍵字。在這裡鎖的物件理論上可以為任何物件。塊同步 public void output ...

Java多執行緒之synchronized關鍵字

package thread public class test class ticket implements runnable try catch interruptedexception e 結果如圖 從結果可以看到能夠實現多執行緒的買票 package thread public class...