博客 / 詳情

返回

關於synchronized-reentrantlock-volatile學習總結1.0

Synchronized

synchronized 是什麼

synchronized是 java 提供的原子性內置鎖,實現基本的同步機制,不支持超時,非公平不可中斷,不支持多條件,基於 JVM 的 Monitor(監視鎖)機制實現,主要解決的是多個線程之間的訪問資源的同步性,可以保證被它修飾的方法或者代碼塊在任意時刻只有一個線程執行,以及保證:

  • 原子性
  • 可見性
  • 有序性

監視器鎖(Monitor)是 JVM 內置的鎖機制,開發者無法直接操作 Monitor,只能通過 synchronized 間接使用它。Monitor 的獲取與釋放對開發者是不可見的,由 JVM 自動管理

synchronized還是排它鎖,當一個線程獲得鎖之後,其他線程就必須等到該線程釋放鎖之後才能獲得鎖,由於java中的線程和操作系統原生線程一一對應,線程被阻塞或者喚醒的時候會從用户態轉換為內核態,這種轉換非常消耗性能。

synchronized 的可重入性

synchronized是可重入的,每獲取一次鎖,計數器加一,釋放鎖時,計數器減一,直到計數器為 0,鎖才會真正釋放。

ReentrantLock

ReentrantLock是 JUC(java.util.concurrent.locks)提供的一個可重入鎖、可中斷、公平鎖/非公平鎖任選的顯式鎖(Explicit Lock)

ReentrantLock 鎖模式

非公平鎖(默認)

獲取鎖的時候會“插隊”,性能高,吞吐量大

公平鎖

FIFO,先來先獲取鎖,但是性能比非公平鎖低

ReentrantLock lock = new ReentrantLock(true);  // true = 公平鎖

ReentrantLock的能力

ReentrantLock底層實現主要是依賴於抽象類AbstractQueuedSynchronizer(AQS),該類提供了基本同步機制的框架,其中包含了隊列,狀態值等。

1、tryLock() – 嘗試獲得鎖,不等待

if (lock.tryLock()) {
    try { ... } finally { lock.unlock(); }
} else {
    System.out.println("獲取鎖失敗");
}

作用:防止線程永久等待 → 適合高性能場景(比如秒殺系統)

2、tryLock(timeout) – 超時獲取鎖

if (lock.tryLock(2, TimeUnit.SECONDS)) {
    try { ... } finally { lock.unlock(); }
}

作用:避免長時間等待,適用於讀寫混用、高併發業務。

3、lockInterruptibly – 可中斷獲取鎖

try {
    lock.lockInterruptibly();
    try { ... } finally { lock.unlock(); }
} catch (InterruptedException e) {
    System.out.println("線程被中斷,放棄等待鎖");
}

作用:在等待鎖期間可取消任務,適用於死鎖檢測等場景。

4、多條件隊列 – Condition

相比於synchronized只有一個wait-set,而ReentrantLock可以創建多個Condition

Condition condition = lock.newCondition();

作用:實現更復雜的線程通信(比如生產者 / 消費者 多條件控制)。

Synchronized VS. ReentrantLock

能力 synchronized ReentrantLock
可重入
公平鎖 ✔(可選)
非阻塞嘗試 tryLock() ✔
可中斷獲取鎖 lockInterruptibly() ✔
超時獲取鎖 tryLock(timeout) ✔
條件隊列 1 個 wait-set 多個 Condition ✔
必須手動釋放鎖 自動 必須 unlock()
使用場景 一般情況用Synchronized就行,比較簡單 比較靈活,支持的功能比較多,在複雜情況下用

volatile

volatile 的作用

主要保證變量的可見性禁止指令重排優化,但是不能保證原子性

1、可見性(Visibility)

多個線程讀寫共享變量,如果不加 volatile:

  • 線程可能讀取到 舊值(因為線程讀的是工作內存副本)
  • volatile 讓線程每次讀取都從 主內存

避免線程間由於緩存一致性問題導致的 “看見” 舊值的現象。

2、禁止指令重排序(ordering)

volatile 會插入內存屏障(Memory Barrier),例如:

  • LoadLoad
  • StoreStore
  • StoreLoad(最強)

從而阻止 JVM 和 CPU 進行重排序

Synchronized VS. volatile

volatile 只保證可見性 + 禁止重排;synchronized 保證原子性 + 可見性 + 有序性。
volatile 是“輕量級讀寫”;synchronized 是“重量級加鎖”。

對比項 volatile synchronized
是否保證原子性 ❌ 不保證 ✔ 保證
可見性 ✔ 保證 ✔ 保證
是否禁止指令重排 ✔ 禁止 ✔ 禁止(通過內存屏障)
是否會阻塞線程 ❌ 不會阻塞 ✔ 可能阻塞(等待鎖)
是否適用於複合操作(i++) ❌ 不適用 ✔ 適用
性能 ⭐ 非常快 🐢 慢(涉及鎖競爭)
底層實現 內存屏障 + volatile 寫入協議 監視器鎖(Monitorenter/monitorexit)
是否可重入 不適用 ✔ 可重入鎖
是否能實現臨界區保護 ❌ 不行 ✔ 可以
適用場景 狀態標誌、DCL 單例、配置刷新 多線程共享修改的臨界區

The end….

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.