1. 程式人生 > >Java併發--synchronized實現原理及鎖優化

Java併發--synchronized實現原理及鎖優化

注:本文中的部分內容摘抄自他人部落格,如有侵權,請聯絡我,侵刪~

本篇部落格主要講述 synchronized 關鍵字的實現原理以及 JDK 1.6 後對 synchronized 的種種優化。synchronized 的使用不再贅述。

博主目前依舊存在的疑惑

請在閱讀完此篇部落格之後,幫助博主回答這三個問題:

  1. 多執行緒爭奪 Monitor 的具體過程是怎樣的?是根據 ObjectMonitor 中的 _count 值判斷當前 Monitor 是否被鎖定嗎?
  2. JVM 如果檢測到在單執行緒環境下執行同步程式碼(StringBuffer),是會進行鎖消除呢,還是會使用偏向鎖?
  3. 對於偏向鎖的撤銷過程及膨脹過程,博主只是在一些部落格的基礎上給出了自己的理解!不權威,建議閱讀原始碼,博主對這部分知識的講解持懷疑態度,如果在閱讀的過程中發現博主對偏向鎖的撤銷與膨脹理解有誤,請指出,感激不盡~(網上基本上沒有從原始碼角度分析的,對於偏向鎖撤銷與升級的詳細過程也是眾說紛紜)

引言

我們先來看一份程式碼:

public class SynchronizedTest {
    public synchronized void test1() {

    }

    public void test2() {
        synchronized (this) {

        }
    }
}

對其進行 javap 反編譯分析:

javap -c SynchronizedTest.class

Compiled from "SynchronizedTest.java"
public class org.xiyoulinux
.SynchronizedTest {
public org.xiyoulinux.SynchronizedTest(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return public synchronized void test1(); Code: 0: return public void test2(); Code: 0: aload_0 1
: dup 2: astore_1 3: monitorenter 4: aload_1 5: monitorexit 6: goto 14 9: astore_2 10: aload_1 11: monitorexit 12: aload_2 13: athrow 14: return Exception table: from to target type 4 6 9 any 9 12 9 any }

對比 javap 的輸出結果,我們做一個簡單的總結:

同步方法:synchronized 方法會被翻譯成普通的方法呼叫。在 JVM 位元組碼層面並沒有任何特別的指令來實現被 synchronized 修飾的方法。在 Class 檔案的方法表中將該方法的 access_flags 欄位中的 synchronized 標誌位置 1,表示該方法是同步方法並使用呼叫該方法的物件(物件鎖)或該方法所屬的 Class(類鎖) 做為鎖物件。

同步塊:monitorenter 指令插入到同步程式碼塊的開始位置,monitorexit 指令插入到同步程式碼塊的結束位置,JVM 需要保證每一個 monitorenter 都有一個 monitorexit 與之相對應。任何物件都有一個 monitor 與之相關聯,當且一個 monitor 被持有之後,他將處於鎖定狀態。執行緒執行到 monitorenter 指令時,將會嘗試獲取物件所對應的 monitor 所有權,即嘗試獲取物件的鎖。(關於上述位元組碼中一個 monitorenter 指令為什麼對應兩個 monitorexit 指令我們稍後進行說明)

synchronized底層語義原理

Java物件頭

要深入理解 synchronized 的實現原理,先來了解一下 Java 物件頭。

物件在堆中由三部分組成:

  1. 物件頭
  2. 例項變數
  3. 填充資料
  • 例項變數:存放類的屬性資料資訊,包括父類的屬性資訊,如果是陣列的例項部分還包括陣列的長度,這部分記憶體按4位元組對齊。
  • 填充資料:由於虛擬機器要求物件起始地址必須是 8 位元組的整數倍。填充資料不是必須存在的,僅僅是為了位元組對齊。
  • 物件頭:HotSpot 虛擬機器的物件頭主要包括兩部分資料:Mark Word(標記欄位)、Class Point(型別指標)。其中 Class Point 是物件指向它的類元資料的指標,虛擬機器通過這個指標來確定這個物件是哪個類的例項,Mark Word 用於儲存物件自身的執行時資料,它是實現輕量級鎖和偏向鎖的關鍵。它還用於儲存物件自身的執行時資料,如雜湊碼(HashCode)、GC分代年齡、鎖狀態標誌、執行緒持有的鎖、偏向執行緒 ID、偏向時間戳等等。

Java 物件頭一般佔有兩個字寬(在 32 位虛擬機器中,1 個字寬等於 4 位元組,也就是 32bit),但是如果物件是陣列型別,則需要三個字寬,因為 JVM 虛擬機器可以通過 Java 物件的元資料資訊確定 Java 物件的大小,但是無法從陣列的元資料來確認陣列的大小,所以用一塊來記錄陣列長度。

物件頭的儲存結構如下:

長度 內容 說明
32/64 bit Mark Word 儲存物件的 hashCode 或鎖資訊等。
32/64 bit Class Metadata Address 儲存到物件型別資料的指標
32/64 bit Array length 陣列的長度(如果當前物件是陣列)

32 位 JVM 的 Mark Word 的預設儲存結構如下:

鎖狀態 25bit 4bit 1bit是否是偏向鎖 2bit 鎖標誌位
無鎖狀態 物件HashCode 物件分代年齡 0 01

由於物件頭的資訊是與物件自身定義的資料沒有關係的額外儲存成本,因此考慮到 JVM 的空間效率,Mark Word 被設計成為一個非固定的資料結構,以便儲存更多有效的資料,它會根據物件本身的狀態複用自己的儲存空間,如 32 位 JVM 下,除了上述列出的 Mark Word 預設儲存結構外,還有如下可能變化的結構:

此處輸入圖片的描述

Monitor(管程)

  • 什麼是 Monitor(管程)?

我們可以把它理解為一個同步工具,也可以描述為一種同步機制,它通常被描述為一個物件。所有的 Java 物件都是天生的 Monitor,在 Java 的設計中 ,每一個 Java 物件都帶了一把看不見的鎖,它叫做內建鎖或者 Monitor 鎖。

觀察 Mark Word 儲存結構的那張圖(上圖):

這裡我們主要分析一下重量級鎖也就是通常說 synchronized 的物件鎖,鎖標識位為 10,其中指標指向的是 monitor 物件(也稱為管程或監視器鎖)的起始地址。每個物件都存在著一個 monitor 與之關聯,物件與其 monitor 之間的關係存在多種實現方式,如 monitor 可以與物件一起建立銷燬或當執行緒試圖獲取物件鎖時自動生成,但當一個 monitor 被某個執行緒持有後,它便處於鎖定狀態。在 Java 虛擬機器(HotSpot)中,monitor 是由 ObjectMonitor 實現的,其主要資料結構如下:(位於 HotSpot 虛擬機器原始碼 ObjectMonitor.cpp 檔案,C++實現)

ObjectMonitor() {
    _header       = NULL;
    _count        = 0;          // 記錄個數
    _waiters      = 0,
    _recursions   = 0;
    _object       = NULL;
    _owner        = NULL;
    _WaitSet      = NULL;       // 處於 wait 狀態的執行緒,會被加入到 _WaitSet
    _WaitSetLock  = 0;
    _Responsible  = NULL;
    _succ         = NULL;
    _cxq          = NULL;
    FreeNext      = NULL;
    _EntryList    = NULL;       // 處於等待鎖 block 狀態的執行緒,會被加入到該列表
    _SpinFreq     = 0;
    _SpinClock    = 0;
    OwnerIsThread = 0;
}

ObjectMonitor 中有兩個佇列,_WaitSet 和 _EntryList,用來儲存 ObjectWaiter 物件列表( 每個等待鎖的執行緒都會被封裝成 ObjectWaiter 物件),_owner 指向持有 ObjectMonitor 物件的執行緒,當多個執行緒同時訪問一段同步程式碼時,首先會進入 _EntryList 集合,當執行緒獲取到物件的 monitor 後會把 monitor 中的 _owner 變數設定為當前執行緒,同時 monitor 中的計數器 _count 加 1。若執行緒呼叫 wait() 方法,將釋放當前持有的 monitor,_owner 變數恢復為 null,_count 自減 1,同時該執行緒進入 _WaitSet 集合中等待被喚醒。若當前執行緒執行完畢也將釋放 monitor(鎖)並復位變數的值,以便其它執行緒進入獲取 monitor(鎖)。

由此看來,monitor 物件存在於每個 Java 物件的物件頭中(儲存的是指標),synchronized 便是通過這種方式獲取鎖的,也是為什麼 Java 中任意物件可以作為鎖的原因,同時也是 notify/notifyAll/wait 等方法存在於頂級物件 Object 中的原因(鎖可以是任意物件,所以可以被任意物件呼叫的方法是定義在 object 類中)。

synchronized方法底層原理

我們在引言部分對 synchronized 方法已經做了一個簡單的總結,現在對它進行一點補充:

在 Java 早期版本中,synchronized 屬於重量級鎖,效率低下,因為監視器鎖(monitor)是依賴於底層作業系統的 Mutex Lock 來實現的,而作業系統實現執行緒之間的切換時需要從使用者態轉換到核心態,這個狀態之間的轉換需要相對比較長的時間,時間成本相對較高,這也是為什麼早期的 synchronized 效率低的原因。慶幸的是在 Java 6 之後 Java 官方從 JVM 層面對 synchronized 進行了較大優化,所以現在的 synchronized 鎖效率也優化得很不錯了。Java 6 之後,為了減少獲得鎖和釋放鎖所帶來的效能消耗,引入了輕量級鎖和偏向鎖,關於鎖優化的內容,我們稍後再談。

synchronized程式碼塊底層原理

在引言部分,我們對 synchronized 程式碼塊也做了一個簡單的總結。同樣,對其做一點補充:

當執行 monitorenter 指令時,當前執行緒將試圖獲取物件鎖所對應的 monitor 的持有權,當物件鎖的 monitor 的進入計數器為 0,那執行緒可以成功取得 monitor,並將計數器值設定為 1,取鎖成功。如果當前執行緒已經擁有物件鎖的 monitor 的持有權,那它可以重入這個 monitor,重入時計數器的值會加 1。倘若其他執行緒已經擁有物件鎖的 monitor 的所有權,那當前執行緒將被阻塞,直到正在執行的執行緒執行完畢,即 monitorexit 指令被執行,執行執行緒將釋放 monitor 並設定計數器值為 0,其他執行緒將有機會持有 monitor。值得注意的是編譯器將會確保無論方法通過何種方式完成,方法中呼叫過的每條 monitorenter 指令都有執行其對應 monitorexit 指令,無論這個方法是正常結束還是異常結束。為了保證在方法異常完成時 monitorenter 和 monitorexit 指令依然可以正確配對執行,編譯器會自動產生一個異常處理器,這個異常處理器可處理所有的異常,它的目的就是用來執行 monitorexit 指令。從位元組碼中也可以看出多了一個 monitorexit 指令。

鎖優化

自旋鎖與自適應自旋

如前面所述,synchronized 在 JDK 1.6 之前之所以被稱為“重量級鎖”,是因為對於互斥同步的效能來說,影響最大的就是阻塞的實現。掛起執行緒與恢復執行緒的操作都需要轉入核心態中完成。從使用者態轉入核心態是比較耗費系統性能的。

研究表明,大多數情況下,執行緒持有鎖的時間都不會太長,如果直接掛起作業系統層面的執行緒可能會得不償失,畢竟作業系統實現執行緒之間的切換時需要從使用者態轉換到核心態,這個狀態之間的轉換需要相對比較長的時間,時間成本相對較高。自旋鎖會假設在不久將來,當前的執行緒可以獲得鎖,因此虛擬機器會讓當前想要獲取鎖的執行緒做幾個空迴圈,使當前執行緒不放棄處理器的執行時間(這也是稱為自旋的原因),在經過若干次迴圈後,如果得到鎖,就順利進入臨界區。

但是自旋不能代替阻塞,首先,自旋鎖需要多處理器或一個處理器擁有多個核心的 CPU 環境,這樣才能保證兩個及以上的執行緒並行執行(一個是獲取鎖的執行執行緒,一個是進行自旋的執行緒)。除了對處理器數量的要求外,自旋雖然避免了執行緒切換的開銷,但它是要佔用處理器時間的,因此,如果鎖被佔用的時間比較短,自旋的效果就比較好,否則只是白白佔用了 CPU 資源,帶來效能上的浪費。

那麼自旋就需要有一定的限度,如果自旋超過了一定的次數後,還沒有成功獲取鎖,就只能進行掛起了,這個次數預設是 10。

在 JDK 1.4.2 中引入了自旋鎖,在 JDK 1.6 中引入了自適應自旋鎖。自適應意味自旋的時間不再固定:

如果同一個鎖物件上,自旋等待剛剛成功獲取鎖,並且持有鎖的執行緒正在執行,那麼虛擬機器就會認為此次自旋也很有可能成功,進而它將允許自旋等待持續相對更長的時間,比如 100 個迴圈。如果對於某個鎖,自旋很少成功獲取過,那麼在以後獲取這個鎖時將可能自動省略掉自旋過程,以避免浪費處理器資源。有了自適應自旋,隨著程式執行和效能監控資訊的不斷完善,虛擬機器對程式鎖的狀況預測就會越來越精準,虛擬機器也就會越來越“聰明”。

鎖消除

消除鎖是虛擬機器另外一種鎖的優化,這種優化更徹底,Java 虛擬機器在 JIT 編譯時(關於 JIT 編譯可以參考我的這篇部落格:JVM–解析執行期優化與JIT編譯器),通過對執行上下文的掃描,去除不可能存在共享資源競爭的鎖,通過這種方式消除沒有必要的鎖,可以節省毫無意義的請求鎖時間。

鎖消除的主要判定依據來源於逃逸分析技術的支援(關於逃逸分析技術可以參考周志明老師所出的《深入理解 Java 虛擬機器》一書中第 11 章內容或自行百度)。

也許你會有疑惑,變數是否逃逸,程式設計師本身應該就可以判斷,怎麼會存在明知道不存在資料爭用的情況下還使用同步?來看如下程式碼:

public String concatString(String s1, String s2, String s3) {
    return s1 + s2 + s3;
}

由於 String 是一個不可變類,因此對字串的連線操作總是通過新生成的 String 物件來進行的,在 JDK 1.5 之前,javac 編譯器會對 String 連線進行自動優化,將連線轉換為 StringBuffer 物件的連續 append 操作,在 JDK 1.5 之後,會轉化為 StringBuilder 物件的連續 append 操作。也就是說,上述程式碼經過 javac 優化之後,有可能變為下面這樣:

public String concatString(String s1, String s2, String s3) {
    StringBuffer sb = new StringBuffer();
    sb.append(s1);
    sb.append(s2);
    sb.append(s3);

    return sb.toString();
}

StringBuffer 是一個執行緒安全的類,在它的 append 方法中有一個同步塊,鎖物件就是 sb,但是虛擬機器觀察變數 sb,發現它是一個區域性變數,本身執行緒安全,並不需要額外的同步機制。因此,這裡雖然有鎖,但可以被安全的清除,在 JIT 編譯之後,這段程式碼就會忽略掉所有的同步而直接執行。這就是鎖消除。

鎖粗化

原則上,我們在使用同步塊的時候,總是建議將同步塊的作用範圍限制的儘量小—使需要同步的運算元量儘可能變小,在存在鎖競爭的情況下,等待鎖的執行緒可以儘快的拿到鎖。

大部分情況下,上述原則都正確,但是存在特殊情況,如果一系列操作下來,都對同一個物件反覆加鎖與解鎖,甚至加鎖與解鎖操作出現在迴圈體中,那即使沒有執行緒競爭,頻繁的進行互斥同步操作也會導致不必要的效能損耗。

如上述程式碼中的 append 方法。如果虛擬機器探測到了這樣的操作,就會把加鎖的同步範圍擴充套件(粗化)到整個操作序列的外部。以上述程式碼為例,就是擴充套件到第一個 append 操作之前直至最後一個 append 操作之後,這樣只需要加鎖一次。

偏向鎖

偏向鎖會偏向第一個獲取它的執行緒,如果在接下來的執行過程中,該鎖沒有被其他執行緒獲取,則持有偏向鎖的執行緒將永遠不需要進行同步。

HotSpot 的作者經過以往的研究發現大多數情況下鎖不僅不存在多執行緒競爭,而且總是由同一執行緒多次獲得(比如在單執行緒中使用 StringBuffer 類),為了讓執行緒獲得鎖的代價更低而引入了偏向鎖。當鎖物件第一次被執行緒獲取的時候,虛擬機器把物件頭中的標誌位設為“01”,即偏向模式。同時使用 CAS 操作把獲取這個鎖的執行緒 ID 記錄在物件的 Mark Word 中,如果 CAS 操作成功,持有偏向鎖的執行緒以後每次進入這個鎖相關的同步塊時,虛擬機器都可以不用進行任何同步操作。

當有另一個執行緒去嘗試獲取這個鎖時,偏向模式就宣告結束。

此處輸入圖片的描述

如上圖,當執行緒 2 爭奪鎖物件時,偏向模式宣告結束。由執行緒 2 通知執行緒 1 進行偏向鎖的撤銷,此時執行緒 1 在全域性安全點(沒有位元組碼執行的地方)處進行暫停,進行解鎖操作。

偏向鎖只能被第一個獲取它的執行緒進行 CAS 操作,一旦出現執行緒競爭鎖物件,其它執行緒無論何時進行 CAS 操作都會失敗。

在解鎖成功之後,JVM 將判斷當前執行緒的狀態,如果還沒有執行完同步程式碼塊,則直接將偏向鎖膨脹為輕量級鎖,然後繼續執行同步程式碼塊,否則將偏向鎖先撤銷為無鎖狀態,當下一次執行同步程式碼塊的時候再由 JVM 將其膨脹為輕量級鎖。

使用偏向鎖的優點在於在沒有多執行緒競爭的情況下,只需進行一次 CAS 操作,就可執行同步程式碼塊,但是我們也必須保證撤銷偏向鎖所耗費的效能資源要低於省去加鎖取鎖所節省下來的效能資源。

輕量級鎖

偏向鎖一旦受到多執行緒競爭,就會膨脹為輕量級鎖。

偏向鎖在執行同步塊的時候不用做任何同步操作,而輕量級鎖是在多執行緒交替執行同步程式碼塊,不產生執行緒阻塞的情況下使用 CAS 操作去消除同步使用的互斥量。

輕量級鎖加鎖:執行緒在執行同步塊之前,如果同步物件沒有被鎖定,JVM 會先在當前執行緒的棧楨中建立用於儲存鎖記錄(Lock Record)的空間,並將物件頭中的 Mark Word 複製到鎖記錄中,官方稱為 Displaced Mark Word。然後執行緒嘗試使用 CAS 將物件頭中的 Mark Word 替換為指向鎖記錄的指標。如果成功,當前執行緒獲得鎖,如果失敗,表示其他執行緒競爭鎖,當前執行緒便嘗試使用自旋來獲取鎖,如果自旋還是無法獲取到鎖,輕量級鎖便會膨脹為重量級鎖。

輕量級鎖解鎖:輕量級解鎖時,會使用 CAS 操作來將 Displaced Mark Word 替換回到物件頭,如果成功,則表示沒有競爭發生。如果失敗,表示當前鎖存在競爭,鎖就會膨脹成重量級鎖。下圖是兩個執行緒同時爭奪鎖,導致鎖膨脹的流程圖:

此處輸入圖片的描述

如上圖,當執行緒 1 還在使用輕量級鎖執行同步程式碼塊的時候,執行緒 2 嘗試爭奪輕量級鎖,就會失敗,失敗之後執行緒 2 並不會直接將輕量級鎖膨脹為重量級鎖,而是先進行自旋等待,如果成功獲取到鎖,則不進行鎖的膨脹。線上程 2 成功將鎖升級之後,執行緒 2 進行阻塞。執行緒 1 執行完同步程式碼塊之後嘗試 CAS 解鎖,解鎖失敗,發現有執行緒對鎖進行過競爭,則釋放鎖並喚醒等待執行緒。

補充

鎖的升級

鎖主要存在四種狀態,依次是:無鎖狀態、偏向鎖狀態、輕量級鎖狀態、重量級鎖狀態,他們會隨著競爭的激烈而逐漸升級。鎖可以升級不可降級,這種策略是為了提高獲得鎖和釋放鎖的效率。

各個狀態鎖的優缺點對比

優點 缺點 適用場景
偏向鎖 加鎖和解鎖不需要額外的消耗,和執行非同步方法比僅存在納秒級的差距。 如果執行緒間存在鎖競爭,會帶來額外的鎖撤銷的消耗。 適用於只有一個執行緒訪問同步塊場景。
輕量級鎖 競爭的執行緒不會阻塞,提高了程式的響應速度。 始終得不到鎖的執行緒使用自旋會消耗CPU。 追求響應時間。同步塊執行速度非常快。
重量級鎖 執行緒競爭不使用自旋,不會消耗CPU。 執行緒阻塞,響應時間緩慢。 同步塊執行速度較慢。

總結

  1. synchronized 的底層實現主要依靠 Monitor(管程);
  2. 從管程我們需要延伸至 Java 物件頭這一部分;
  3. 瞭解過 Java 物件頭之後,我們可以對 Monitor 的底層實現(ObjectMonitor)再進行簡單的瞭解;
  4. 熟悉多執行緒爭奪 Monitor 的過程;
  5. 最後分類討論同步方法與同步塊;
  6. 熟悉鎖粗化、鎖消除、自旋與自適應自旋等相關概念;
  7. 熟悉偏向鎖、輕量級鎖、重量級鎖的相關概念;
  8. 熟悉偏向鎖、輕量級鎖解鎖的過程;
  9. 熟悉偏向鎖、輕量級鎖、重量級鎖膨脹的過程。

參考閱讀

《深入理解Java虛擬機器》–周志明

相關推薦

Java併發--synchronized實現原理優化

注:本文中的部分內容摘抄自他人部落格,如有侵權,請聯絡我,侵刪~ 本篇部落格主要講述 synchronized 關鍵字的實現原理以及 JDK 1.6 後對 synchronized 的種種優化。synchronized 的使用不再贅述。 博主目前依舊存在

Synchronized實現原理優化

Synchronized及其實現原理Synchronized的基本使用Synchronized是Java中解決併發問題的一種最常用的方法,也是最簡單的一種方法。Synchronized的作用主要有三個:(1)確保執行緒互斥的訪問同步程式碼(2)保證共享變數的修改能夠及時可見(

1.Java集合-HashMap實現原理源碼分析

int -1 詳細 鏈接 理解 dac hash函數 順序存儲結構 對象儲存   哈希表(Hash Table)也叫散列表,是一種非常重要的數據結構,應用場景及其豐富,許多緩存技術(比如memcached)的核心其實就是在內存中維護一張大的哈希表,而HashMap的實

Java併發程式設計(二)——Java併發底層實現原理

Java程式碼會被編譯後變成Java位元組碼,位元組碼會被類載入器載入到JVM中,JVM執行位元組碼,最終轉化成彙編指令在CPU上執行,Java中所使用的併發機制依賴於JVM的實現和CPU的指令。 volatile 在多執行緒併發程式設計中,synchronized和volatile

JAVA架構-SpringMVC實現原理解析

                               1、Spring mvc介紹 SpringMVC框架是以請求為驅動,圍繞Servlet設計,將請求發給控制器,然後通過模型物件,分派器來展示請求結果檢視。其中核心類是DispatcherServlet,它是一個S

Java併發容器ConcurrentHashMap原理HashMap死迴圈原因的分析

HashMap是我們最常用的資料結構之一,它方便高效,但遺憾的是,HashMap是執行緒不安全的,在併發環境下,在HashMap的擴容過程中,可能造成散列表的迴圈鎖死。而執行緒安全的HashTable使用了大量Synchronized鎖,導致了效率非常低下。幸運的是,併發程

【轉】MySQL—1、資料庫索引的實現原理查詢優化

MySQL官方對索引的定義為:索引(Index)是幫助MySQL高效獲取資料的資料結構。 使用索引的目的在於提高查詢效率,這篇文章梳理一下索引的實現原理和應用。 不同的儲存引擎索引實現的資料結構不同 MySQL支援諸多儲存引擎,而各種儲存引擎對索引的支援也各不相同,

synchronized實現原理ReentrantLock原始碼

#### synchronized ###### synchronized的作用範圍 ``` public class SynchronizedTest { // 例項方法,方法訪問標誌ACC_SYNCHRONIZED,鎖物件是物件例項 public synchronized void t

Synchronized用法原理優化升級過程(面試)

簡介 多執行緒一直是面試中的重點和難點,無論你現在處於啥級別段位,對synchronized關鍵字的學習避免不了,這是我的心得體會。下面咱們以面試的思維來對synchronized做一個系統的描述,如果有面試官問你,說說你對synchronized的理解?你可以從synchronized使用層面,synch

Javasynchronized實現原理偏向、輕量級、自旋、公平簡介

    在多執行緒程式設計中,synchronized 一直都是元老級別的存在,很多人都稱之為重量級鎖。本文來簡單介紹synchronized的實現原理,以及為減少獲得鎖和釋放鎖所帶來的效能損耗而引進的偏向鎖與輕量級鎖。     Java中使用synchronized來實現

JAVA synchronized實現原理以及其中優化的歸納總結

在java中存在兩種鎖機制,分別是synchronized和Lock。Lock介面和實現類是JDK5新增的內容,而synchronized在JDK6開始提供了一系列的鎖優化,下面總結一下synchronized的實現原理和涉及的一些鎖優化機制 1.sync

Java併發(三):synchronized實現原理

一、synchronized用法 Java中的同步塊用synchronized標記。 同步塊在Java中是同步在某個物件上(監視器物件)。 所有同步在一個物件上的同步塊在同時只能被一個執行緒進入並執行操作。 所有其他等待進入該同步塊的執行緒將被阻塞,直到執行該同步塊中的執行緒退出。 (注:不要使用全

深入理解Java併發synchronized實現原理

關聯文章: 本篇主要是對Java併發中synchronized關鍵字進行較為深入的探索,這些知識點結合博主對synchronized的個人理解以及相關的書籍的講解(在結尾參考資料),如有誤處,歡迎留言。 執行緒安全是併發程式

Java併發程式設計的藝術——volatile和synchronized實現原理

volatile volatile變數修飾的共享變數進行寫操作時候,會多出lock字首指令。 lock字首指令在多核處理器下會引發一下兩件事情: 將當前處理器快取行的資料寫回到系統記憶體。 這個寫回記

java併發-Synchronized+CAS方式實現讀寫

Synchronized+CAS方式實現讀寫鎖 文章目錄 Synchronized+CAS方式實現讀寫鎖 思路 技術 程式碼 測試 結果 [GitHub主頁](https://gith

Java併發——Synchronized優化(輕量級、偏向

1 重量級鎖 在上一篇部落格中我們知道,Synchronized的實現依賴於與某個物件向關聯的monitor(監視器)實現,而monitor是基於底層作業系統的Mutex Lock實現的,而基於Mutex Lock實現的同步必須經歷從使用者態到核心態的轉換,這

java共享實現原理CountDownLatch解析

前言 前面介紹了ReentrantLock,又叫排他鎖,本篇主要通過CountDownLatch的學習來了解java併發包中是如何實現共享鎖的。 CountDownLatch使用解說 CountDownLatch是java5中新增的一個併發工具類,

原始碼閱讀:Java併發synchronized實現原理

執行緒安全是併發程式設計中的重要關注點,應該注意到的是,造成執行緒安全問題的主要誘因有兩點,一是存在共享資料(也稱臨界資源),二是存在多條執行緒共同操作共享資料。因此為了解決這個問題,我們可能需要這樣一個方案,當存在多個執行緒操作共享資料時,需要保證同一時刻有且

深入理解 Java 併發synchronized 實現原理

關聯文章深入理解Java型別資訊(Class物件)與反射機制深入理解Java列舉型別(enum)深入理解Java註解型別(@Annotation)深入理解Java併發之synchronized實現原理本篇主要是對Java併發中synchronized關鍵字進行較為深入的探索,這些知識點結合博主對synchro

java 併發synchronized 實現原理

在 java 開發中 synchronized 是使用的最多的工具。 表現形式 在 java 中每個物件都可以作為鎖: 對於普通同步方法,鎖是當前例項物件; 對於靜態同步方法,鎖是當前類的 Class 物件; 對於同步方法快,鎖是 Synchronized 括