最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java?中的?synchronized?關(guān)鍵字詳解

 更新時(shí)間:2025年11月06日 09:54:09   作者:祈禱蒼天賜我java之術(shù)  
本文詳細(xì)介紹了Java中的synchronized關(guān)鍵字,包括其基本概念、工作原理、使用場(chǎng)景、性能優(yōu)化技巧以及常見(jiàn)問(wèn)題與解決方案,感興趣的朋友跟隨小編一起看看吧

一、synchronized 關(guān)鍵字的基礎(chǔ)認(rèn)知

1.1 什么是 synchronized?

synchronized 是 Java 中用于實(shí)現(xiàn)線程同步的關(guān)鍵字,它提供了內(nèi)置的鎖機(jī)制來(lái)協(xié)調(diào)多線程對(duì)共享資源的訪問(wèn)。在 Java 并發(fā)編程中,synchronized 是最基本、最常用的同步手段之一。

工作原理

synchronized 通過(guò)對(duì)象監(jiān)視器(Monitor)機(jī)制實(shí)現(xiàn)同步。當(dāng)線程進(jìn)入 synchronized 代碼塊時(shí):

  1. 首先嘗試獲取對(duì)象的監(jiān)視器鎖(Monitor Lock)
  2. 如果鎖可用,線程獲取鎖并進(jìn)入同步塊
  3. 如果鎖被其他線程持有,當(dāng)前線程進(jìn)入阻塞狀態(tài),直到鎖被釋放
  4. 線程執(zhí)行完同步代碼后自動(dòng)釋放鎖

鎖的存儲(chǔ)位置

在 JVM 中,每個(gè)對(duì)象都有一個(gè)對(duì)象頭(Object Header),其中包含兩部分重要信息:

  • Mark Word:存儲(chǔ)對(duì)象的哈希碼、GC 分代年齡等信息
  • Klass Pointer:指向?qū)ο箢愋蛿?shù)據(jù)的指針
  • 如果是數(shù)組對(duì)象,還會(huì)有數(shù)組長(zhǎng)度信息

synchronized 使用的鎖信息就存儲(chǔ)在 Mark Word 中,包括:

  • 鎖狀態(tài)標(biāo)志位
  • 指向鎖記錄的指針
  • 指向重量級(jí)鎖的指針
  • 偏向線程 ID 等

1.2 synchronized 的核心作用

1.2.1 原子性保障

原子性是指一個(gè)操作不可中斷,要么全部執(zhí)行成功,要么全部不執(zhí)行。synchronized 通過(guò)互斥鎖機(jī)制保證被其修飾的代碼塊的原子性執(zhí)行。

典型應(yīng)用場(chǎng)景:

public class Counter {
    private int count = 0;
    public synchronized void increment() {
        count++; // 非原子操作變?yōu)樵硬僮?
    }
}

在這個(gè)例子中,count++ 操作實(shí)際上包含三個(gè)步驟:

  1. 讀取 count 的值
  2. 將值加 1
  3. 寫回新值 如果沒(méi)有 synchronized,多線程環(huán)境下可能導(dǎo)致更新丟失。

1.2.2 可見(jiàn)性保障

可見(jiàn)性是指當(dāng)一個(gè)線程修改了共享變量的值后,其他線程能夠立即看到修改后的值。synchronized 通過(guò)以下機(jī)制保證可見(jiàn)性:

  • 線程獲取鎖時(shí):
    • 清空工作內(nèi)存(本地內(nèi)存)中的變量副本
    • 從主內(nèi)存重新讀取最新值
  • 線程釋放鎖時(shí):
    • 將工作內(nèi)存中修改過(guò)的變量刷新到主內(nèi)存
    • 確保其他線程能看到最新修改

這符合 JMM(Java 內(nèi)存模型)的 happens-before 原則中的監(jiān)視器鎖規(guī)則:對(duì)一個(gè)鎖的解鎖 happens-before 于隨后對(duì)這個(gè)鎖的加鎖。

1.2.3 有序性保障

有序性是指程序執(zhí)行的順序按照代碼的先后順序執(zhí)行。synchronized 通過(guò)以下方式保證有序性:

  1. 禁止指令重排序:編譯器不會(huì)對(duì)同步塊內(nèi)的指令進(jìn)行重排序優(yōu)化
  2. 建立內(nèi)存屏障(Memory Barrier):確保同步塊內(nèi)的指令不會(huì)"逃逸"到同步塊之外執(zhí)行

示例:

public class Singleton {
    private static Singleton instance;
    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton(); // 保證new操作的原子性和有序性
        }
        return instance;
    }
}

二、synchronized 的使用場(chǎng)景及語(yǔ)法詳解

synchronized 是 Java 中最基本的同步機(jī)制,用于解決多線程環(huán)境下的線程安全問(wèn)題。它主要有三種使用方式,每種方式對(duì)應(yīng)不同的鎖對(duì)象和同步范圍,適用于不同的并發(fā)場(chǎng)景。

2.1 修飾實(shí)例方法

詳細(xì)說(shuō)明

當(dāng) synchronized 修飾實(shí)例方法時(shí),鎖對(duì)象是當(dāng)前類的實(shí)例對(duì)象(即 this 對(duì)象)。這種同步方式適用于需要保護(hù)實(shí)例變量的場(chǎng)景,如:

  • 銀行賬戶的余額操作
  • 購(gòu)物車的商品數(shù)量修改
  • 計(jì)數(shù)器對(duì)象的自增操作

典型應(yīng)用場(chǎng)景

假設(shè)我們有一個(gè)銀行賬戶類,需要保證多線程環(huán)境下存款操作的原子性:

public class BankAccount {
    private double balance;
    // 使用synchronized修飾實(shí)例方法保證線程安全
    public synchronized void deposit(double amount) {
        double newBalance = balance + amount;
        try {
            // 模擬耗時(shí)操作
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        balance = newBalance;
    }
    public synchronized double getBalance() {
        return balance;
    }
}

注意事項(xiàng)

  1. 這種同步方式只對(duì)同一個(gè)實(shí)例對(duì)象的方法調(diào)用有效
  2. 不同實(shí)例對(duì)象的方法調(diào)用不會(huì)互斥
  3. 方法執(zhí)行期間會(huì)阻塞其他線程調(diào)用同一實(shí)例的同步方法
  4. 應(yīng)避免在同步方法中執(zhí)行長(zhǎng)時(shí)間操作,以免影響性能

鎖范圍示意圖

[實(shí)例對(duì)象A]
├── 同步方法1 (鎖A)
└── 同步方法2 (鎖A)
[實(shí)例對(duì)象B]
├── 同步方法1 (鎖B)
└── 同步方法2 (鎖B)

2.2 修飾靜態(tài)方法

詳細(xì)說(shuō)明

當(dāng) synchronized 修飾靜態(tài)方法時(shí),鎖對(duì)象是當(dāng)前類的 Class 對(duì)象。這種同步方式適用于:

  • 靜態(tài)變量的操作
  • 類級(jí)別的共享資源訪問(wèn)
  • 單例模式的實(shí)現(xiàn)

典型應(yīng)用場(chǎng)景

例如,我們需要一個(gè)全局計(jì)數(shù)器來(lái)統(tǒng)計(jì)所有實(shí)例的創(chuàng)建次數(shù):

public class InstanceCounter {
    private static int count = 0;
    // 靜態(tài)同步方法保證類變量的線程安全
    public static synchronized void increment() {
        count++;
    }
    public static synchronized int getCount() {
        return count;
    }
    public InstanceCounter() {
        increment();
    }
}

執(zhí)行特點(diǎn)

  1. 無(wú)論創(chuàng)建多少個(gè)實(shí)例對(duì)象,靜態(tài)同步方法都會(huì)互斥執(zhí)行
  2. 類加載時(shí)就會(huì)初始化 Class 對(duì)象,全局唯一
  3. 靜態(tài)同步方法和實(shí)例同步方法使用不同的鎖,不會(huì)互相阻塞

鎖范圍示意圖

[Class對(duì)象]
└── 靜態(tài)同步方法 (鎖Class)
[實(shí)例對(duì)象A] [實(shí)例對(duì)象B] ...

2.3 修飾代碼塊

詳細(xì)說(shuō)明

synchronized 代碼塊是最靈活的同步方式,可以顯式指定鎖對(duì)象,適用于:

  • 只需要同步部分代碼而非整個(gè)方法
  • 需要細(xì)粒度控制同步范圍
  • 使用非this對(duì)象作為鎖的情況

三種常見(jiàn)用法詳解

1. 使用 this 作為鎖對(duì)象
public void doSomething() {
    // 非同步代碼
    System.out.println("非同步代碼");
    // 同步代碼塊
    synchronized (this) {
        // 需要同步的代碼
        System.out.println("同步代碼塊");
    }
}

特點(diǎn):等同于同步實(shí)例方法,但可以只同步部分代碼

2. 使用 Class 對(duì)象作為鎖對(duì)象
public void doSomething() {
    synchronized (MyClass.class) {
        // 需要同步的靜態(tài)資源操作
        System.out.println("同步靜態(tài)資源");
    }
}

特點(diǎn):等同于靜態(tài)同步方法,但可以只在需要的地方加鎖

3. 使用自定義對(duì)象作為鎖對(duì)象
private final Object lock = new Object();
public void doSomething() {
    synchronized (lock) {
        // 需要同步的代碼
        System.out.println("使用自定義鎖");
    }
}

優(yōu)勢(shì)

  • 可以創(chuàng)建多個(gè)鎖對(duì)象實(shí)現(xiàn)更細(xì)粒度的控制
  • 避免直接使用this或Class對(duì)象可能導(dǎo)致的問(wèn)題
  • 鎖對(duì)象通常聲明為final防止意外修改

典型應(yīng)用場(chǎng)景:雙重檢查鎖定單例模式

public class Singleton {
    private static volatile Singleton instance;
    private static final Object lock = new Object();
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (lock) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

性能優(yōu)化建議

  1. 盡量減小同步代碼塊的范圍
  2. 避免在同步塊中調(diào)用耗時(shí)操作(如IO)
  3. 對(duì)于讀多寫少的場(chǎng)景,考慮使用讀寫鎖
  4. 不同功能使用不同鎖對(duì)象,減少鎖競(jìng)爭(zhēng)

鎖選擇策略

鎖類型適用場(chǎng)景優(yōu)點(diǎn)缺點(diǎn)
實(shí)例鎖保護(hù)實(shí)例變量簡(jiǎn)單直接粒度較粗
類鎖保護(hù)靜態(tài)變量全局控制可能影響性能
代碼塊鎖需要細(xì)粒度控制靈活高效實(shí)現(xiàn)較復(fù)雜

三、synchronized 的底層實(shí)現(xiàn)原理

要深入理解 synchronized 的工作機(jī)制,需要從 JVM 底層實(shí)現(xiàn)進(jìn)行分析。在 JDK 1.6 之前,synchronized 被稱為"重量級(jí)鎖",因?yàn)樗膶?shí)現(xiàn)完全依賴于操作系統(tǒng)的互斥量(Mutex)機(jī)制,每次線程的阻塞和喚醒都需要在用戶態(tài)和內(nèi)核態(tài)之間切換,帶來(lái)較大的性能開(kāi)銷。根據(jù)測(cè)試數(shù)據(jù),這種上下文切換的開(kāi)銷可能達(dá)到幾十微秒級(jí)別,對(duì)于高并發(fā)場(chǎng)景影響顯著。

JDK 1.6 及之后的版本中,HotSpot 虛擬機(jī)團(tuán)隊(duì)對(duì) synchronized 進(jìn)行了重大優(yōu)化,引入了全新的鎖升級(jí)機(jī)制,包括偏向鎖、輕量級(jí)鎖等概念,使其性能得到極大提升。在大多數(shù)低競(jìng)爭(zhēng)場(chǎng)景下,性能表現(xiàn)甚至可以與 java.util.concurrent 包中的顯式鎖相媲美。

3.1 對(duì)象頭:鎖的存儲(chǔ)載體

在 Java 對(duì)象的內(nèi)存布局中,每個(gè)對(duì)象都包含以下三部分:

  1. 對(duì)象頭(Object Header):存儲(chǔ)對(duì)象運(yùn)行時(shí)數(shù)據(jù)
  2. 實(shí)例數(shù)據(jù)(Instance Data):存儲(chǔ)對(duì)象的實(shí)際字段信息
  3. 對(duì)齊填充(Padding):為了字節(jié)對(duì)齊而存在的填充數(shù)據(jù)

以 32 位 JVM 為例,普通對(duì)象的對(duì)象頭結(jié)構(gòu)如下表所示:

長(zhǎng)度(bit)內(nèi)容詳細(xì)說(shuō)明
25哈希碼(HashCode)對(duì)象的哈希值,用于哈希表等數(shù)據(jù)結(jié)構(gòu)
4GC 分代年齡記錄對(duì)象被 GC 標(biāo)記的次數(shù),達(dá)到閾值(默認(rèn)15)會(huì)被移入老年代
1是否偏向鎖(biased_lock)0表示非偏向鎖,1表示偏向鎖
2鎖狀態(tài)標(biāo)志(lock)01:無(wú)鎖;00:輕量級(jí)鎖;10:重量級(jí)鎖;11:GC標(biāo)記
2(數(shù)組對(duì)象)數(shù)組長(zhǎng)度僅數(shù)組對(duì)象擁有,記錄數(shù)組長(zhǎng)度

當(dāng)對(duì)象作為 synchronized 的鎖對(duì)象時(shí),JVM 主要通過(guò)修改對(duì)象頭中的"鎖狀態(tài)標(biāo)志"和"是否偏向鎖"字段來(lái)記錄鎖狀態(tài)。這里需要注意,在 64 位 JVM 中,對(duì)象頭的結(jié)構(gòu)會(huì)有所不同,但基本原理相同。

3.2 鎖的升級(jí)過(guò)程:從偏向鎖到重量級(jí)鎖

JDK 1.6 引入的鎖升級(jí)機(jī)制是 synchronized 性能優(yōu)化的核心,其升級(jí)路徑為: 無(wú)鎖 → 偏向鎖 → 輕量級(jí)鎖 → 重量級(jí)鎖 這個(gè)過(guò)程是單向的,一旦升級(jí)到重量級(jí)鎖就不會(huì)再降級(jí)。

3.2.1 無(wú)鎖狀態(tài)(Lock-Free)

初始狀態(tài)下,對(duì)象處于無(wú)鎖狀態(tài):

  • 鎖狀態(tài)標(biāo)志:01
  • 是否偏向鎖:0

此時(shí)任何線程都可以通過(guò) CAS 操作嘗試獲取鎖。

3.2.2 偏向鎖(Biased Locking)

設(shè)計(jì)背景:統(tǒng)計(jì)表明,大多數(shù)情況下鎖不僅不存在多線程競(jìng)爭(zhēng),而且總是由同一個(gè)線程多次獲得。例如 GUI 應(yīng)用中的事件分發(fā)線程、消息隊(duì)列的消費(fèi)線程等。

工作流程:

  1. 首次獲取鎖時(shí),JVM 通過(guò) CAS 操作將:
    • 是否偏向鎖置為1
    • 鎖狀態(tài)標(biāo)志保持01
    • 將當(dāng)前線程ID寫入對(duì)象頭
  2. 之后同一線程再次獲取鎖時(shí),只需簡(jiǎn)單檢查線程ID即可,無(wú)需任何同步操作
  3. 當(dāng)其他線程嘗試獲取鎖時(shí),偏向模式立即結(jié)束,可能升級(jí)為輕量級(jí)鎖

性能優(yōu)勢(shì):完全避免了同步操作,獲取鎖的代價(jià)降低到只需一次內(nèi)存訪問(wèn)。

3.2.3 輕量級(jí)鎖(Lightweight Locking)

適用場(chǎng)景:多個(gè)線程交替執(zhí)行同步塊,但基本不會(huì)同時(shí)競(jìng)爭(zhēng)鎖的情況。例如生產(chǎn)者-消費(fèi)者模式中生產(chǎn)者和消費(fèi)者線程的交替執(zhí)行。

詳細(xì)工作流程:

  1. 在棧幀中創(chuàng)建鎖記錄(Lock Record),包含:
    • Displaced Mark Word:對(duì)象頭原始內(nèi)容的拷貝
    • 指向鎖對(duì)象的指針
  2. 通過(guò) CAS 操作嘗試將對(duì)象頭的 Mark Word 替換為指向鎖記錄的指針
  3. 如果成功:
    • 鎖狀態(tài)標(biāo)志變?yōu)?0
    • 線程獲得輕量級(jí)鎖
  4. 如果失?。?ul>
  5. 檢查是否當(dāng)前線程已持有鎖(重入情況)
  6. 否則開(kāi)始自旋等待(自適應(yīng)自旋)
  7. 自旋失敗后升級(jí)為重量級(jí)鎖

自旋優(yōu)化:JVM 采用自適應(yīng)自旋策略,會(huì)根據(jù)之前自旋的成功率動(dòng)態(tài)調(diào)整自旋次數(shù)。

3.2.4 重量級(jí)鎖(Heavyweight Locking)

核心組件:

  • 監(jiān)視器(Monitor):每個(gè)Java對(duì)象都關(guān)聯(lián)一個(gè)Monitor
  • 等待隊(duì)列(Entry Set):存放等待獲取鎖的線程
  • 等待池(Wait Set):存放調(diào)用了wait()的線程

工作流程:

  1. 當(dāng)鎖升級(jí)為重量級(jí)鎖后:
    • 鎖狀態(tài)標(biāo)志變?yōu)?0
    • Mark Word 指向Monitor對(duì)象
  2. 線程競(jìng)爭(zhēng)鎖時(shí):
    • 成功則執(zhí)行同步代碼
    • 失敗則進(jìn)入阻塞狀態(tài),加入等待隊(duì)列
  3. 鎖釋放時(shí):
    • 喚醒等待隊(duì)列中的線程
    • 被喚醒線程需要重新競(jìng)爭(zhēng)鎖

性能特點(diǎn):

  • 線程阻塞和喚醒涉及操作系統(tǒng)內(nèi)核操作
  • 上下文切換開(kāi)銷較大(約5-10μs)
  • 適合鎖競(jìng)爭(zhēng)激烈且持有時(shí)間長(zhǎng)的場(chǎng)景

鎖升級(jí)過(guò)程示例

假設(shè)有一個(gè)同步方法:

public synchronized void increment() {
    count++;
}
  1. 初始調(diào)用(線程A):無(wú)鎖 → 偏向鎖,對(duì)象頭記錄線程A ID
  2. 線程A再次調(diào)用:直接通過(guò)偏向鎖訪問(wèn)
  3. 線程B首次調(diào)用:撤銷偏向鎖 → 輕量級(jí)鎖,線程B通過(guò)CAS獲取鎖
  4. 線程A和B交替調(diào)用:維持輕量級(jí)鎖狀態(tài)
  5. 線程A和B同時(shí)競(jìng)爭(zhēng):輕量級(jí)鎖 → 重量級(jí)鎖,線程阻塞,進(jìn)入等待隊(duì)列

這種漸進(jìn)式的鎖升級(jí)策略,使得 synchronized 在各種競(jìng)爭(zhēng)程度下都能保持較好的性能表現(xiàn)。

四、synchronized 的性能優(yōu)化技巧

4.1 減小鎖粒度:拆分鎖對(duì)象,降低競(jìng)爭(zhēng)頻率

核心原理

通過(guò)將一個(gè)大鎖拆分為多個(gè)小鎖,允許不同線程同時(shí)訪問(wèn)不同的資源分區(qū),從而提升系統(tǒng)吞吐量。這種技術(shù)特別適用于讀多寫少的場(chǎng)景,或者在數(shù)據(jù)可以自然分片的場(chǎng)景中。

實(shí)現(xiàn)細(xì)節(jié)

  1. 分區(qū)策略:通常采用哈希算法將數(shù)據(jù)分配到不同的分區(qū),確保數(shù)據(jù)分布均勻
  2. 鎖數(shù)量:一般設(shè)置為2的冪次方,便于位運(yùn)算優(yōu)化
  3. 擴(kuò)容處理:需要考慮動(dòng)態(tài)擴(kuò)容時(shí)的鎖遷移問(wèn)題

高級(jí)應(yīng)用場(chǎng)景

  • 分布式系統(tǒng)中的分片策略
  • 數(shù)據(jù)庫(kù)連接池的并發(fā)控制
  • 多級(jí)緩存系統(tǒng)的同步機(jī)制

性能對(duì)比

鎖策略并發(fā)度內(nèi)存開(kāi)銷實(shí)現(xiàn)復(fù)雜度
全局鎖簡(jiǎn)單
分段鎖中等中等
細(xì)粒度鎖最高復(fù)雜

4.2 避免鎖競(jìng)爭(zhēng):減少持有鎖的時(shí)間

優(yōu)化原則

  1. 臨界區(qū)最小化:只將真正需要同步的代碼放入同步塊
  2. 計(jì)算與同步分離:將復(fù)雜計(jì)算移到鎖外執(zhí)行
  3. 資源準(zhǔn)備前置:在獲取鎖前完成所有準(zhǔn)備工作

典型錯(cuò)誤模式

// 錯(cuò)誤示例:在鎖內(nèi)執(zhí)行IO操作
synchronized(lock) {
    readFile();  // 耗時(shí)IO
    processData();
    writeFile(); // 耗時(shí)IO
}

最佳實(shí)踐

  1. 使用局部變量暫存計(jì)算結(jié)果
  2. 采用讀寫鎖分離讀寫操作
  3. 對(duì)長(zhǎng)時(shí)間操作實(shí)現(xiàn)可中斷鎖

性能影響

  • 鎖持有時(shí)間減少50%,吞吐量可提升2-3倍
  • 對(duì)于高頻交易系統(tǒng),這種優(yōu)化效果尤為明顯

4.3 利用鎖消除:避免不必要的加鎖

JVM優(yōu)化機(jī)制

  1. 逃逸分析:判斷對(duì)象是否可能被其他線程訪問(wèn)
  2. 棧封閉:確認(rèn)對(duì)象生命周期僅限于當(dāng)前棧幀
  3. 同步消除:移除不必要的同步操作

適用條件

  1. 鎖對(duì)象是方法局部變量
  2. 鎖對(duì)象不會(huì)逃逸出當(dāng)前線程
  3. 同步塊內(nèi)沒(méi)有訪問(wèn)共享資源

驗(yàn)證方法

# 禁用鎖消除進(jìn)行對(duì)比測(cè)試
java -XX:-EliminateLocks LockEliminationDemo

實(shí)際應(yīng)用

  • 工具類方法中的臨時(shí)同步
  • 不可變對(duì)象處理
  • 線程封閉場(chǎng)景

4.4 合理使用鎖粗化:減少鎖的獲取與釋放次數(shù)

觸發(fā)條件

  1. 連續(xù)多次對(duì)同一鎖的獲取/釋放
  2. 循環(huán)體內(nèi)的同步操作
  3. 相鄰的同步代碼塊

實(shí)現(xiàn)方式

  1. JVM自動(dòng)優(yōu)化:HotSpot虛擬機(jī)會(huì)自動(dòng)檢測(cè)并優(yōu)化
  2. 手動(dòng)合并:開(kāi)發(fā)人員顯式擴(kuò)大同步范圍

權(quán)衡考慮

因素鎖細(xì)化鎖粗化
并發(fā)度
鎖開(kāi)銷
適用場(chǎng)景競(jìng)爭(zhēng)激烈操作密集

典型應(yīng)用

  1. 批量數(shù)據(jù)處理
  2. 事務(wù)性操作
  3. 流水線處理

優(yōu)化示例

// 優(yōu)化前:頻繁加鎖
for (Item item : items) {
    synchronized(lock) {
        process(item);
    }
}
// 優(yōu)化后:?jiǎn)未渭渔i
synchronized(lock) {
    for (Item item : items) {
        process(item);
    }
}

注意:鎖粗化可能會(huì)降低并發(fā)度,需根據(jù)實(shí)際場(chǎng)景權(quán)衡使用。

五、synchronized 的常見(jiàn)問(wèn)題與解決方案

5.1 死鎖:線程間相互等待鎖資源

問(wèn)題描述

死鎖是指兩個(gè)或多個(gè)線程在執(zhí)行過(guò)程中,因爭(zhēng)奪鎖資源而相互等待的一種狀態(tài)。例如,線程 A 持有鎖 1,等待鎖 2;線程 B 持有鎖 2,等待鎖 1,此時(shí)兩個(gè)線程會(huì)一直相互等待,無(wú)法繼續(xù)執(zhí)行。

代碼示例(死鎖場(chǎng)景)

public class DeadLockDemo {
    // 兩個(gè)不同的鎖對(duì)象
    private final Object lock1 = new Object();
    private final Object lock2 = new Object();
    // 線程1執(zhí)行的方法:先獲取lock1,再獲取lock2
    public void method1() {
        synchronized (lock1) {
            System.out.println(Thread.currentThread().getName() + " 獲取lock1,等待lock2");
            try {
                Thread.sleep(100); // 模擬耗時(shí)操作,增加死鎖概率
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (lock2) {
                System.out.println(Thread.currentThread().getName() + " 獲取lock2,執(zhí)行method1");
            }
        }
    }
    // 線程2執(zhí)行的方法:先獲取lock2,再獲取lock1
    public void method2() {
        synchronized (lock2) {
            System.out.println(Thread.currentThread().getName() + " 獲取lock2,等待lock1");
            try {
                Thread.sleep(100); // 模擬耗時(shí)操作,增加死鎖概率
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (lock1) {
                System.out.println(Thread.currentThread().getName() + " 獲取lock1,執(zhí)行method2");
            }
        }
    }
    public static void main(String[] args) {
        DeadLockDemo demo = new DeadLockDemo();
        // 線程1執(zhí)行method1
        new Thread(demo::method1, "線程1").start();
        // 線程2執(zhí)行method2
        new Thread(demo::method2, "線程2").start();
    }
}

執(zhí)行結(jié)果

線程 1 會(huì)輸出"獲取 lock1,等待 lock2",線程 2 會(huì)輸出"獲取 lock2,等待 lock1",之后兩個(gè)線程會(huì)一直阻塞,無(wú)法繼續(xù)執(zhí)行,形成死鎖。

死鎖產(chǎn)生的必要條件

  1. 互斥條件:鎖資源只能被一個(gè)線程持有。
  2. 請(qǐng)求與保持條件:線程持有一個(gè)鎖后,又請(qǐng)求其他鎖,且不釋放已持有的鎖。
  3. 不可剝奪條件:線程持有的鎖不能被其他線程強(qiáng)制剝奪,只能由線程自己釋放。
  4. 循環(huán)等待條件:多個(gè)線程形成環(huán)形等待鎖資源的關(guān)系(如線程 A 等線程 B 的鎖,線程 B 等線程 A 的鎖)。

解決方案

只要破壞死鎖產(chǎn)生的任意一個(gè)必要條件,即可避免死鎖。在實(shí)際開(kāi)發(fā)中,常用的解決方案如下:

  1. 按固定順序獲取鎖:確保所有線程都按照相同的順序獲取多個(gè)鎖。例如,在上述示例中,讓method2也先獲取lock1,再獲取lock2,即可避免循環(huán)等待條件。
// 優(yōu)化后的method2:按固定順序獲取鎖(先lock1,再lock2)
public void method2() {
    synchronized (lock1) { // 與method1的鎖獲取順序一致
        System.out.println(Thread.currentThread().getName() + " 獲取lock1,等待lock2");
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        synchronized (lock2) {
            System.out.println(Thread.currentThread().getName() + " 獲取lock2,執(zhí)行method2");
        }
    }
}
  • 使用tryLock()嘗試獲取鎖:使用java.util.concurrent.locks.Lock接口的tryLock(long timeout, TimeUnit unit)方法,在指定時(shí)間內(nèi)嘗試獲取鎖。如果超時(shí)未獲取到鎖,則釋放已持有的鎖,避免線程永久阻塞。
  • 定時(shí)釋放鎖:在持有鎖的線程中,設(shè)置超時(shí)機(jī)制,當(dāng)超過(guò)指定時(shí)間仍未獲取到其他鎖時(shí),主動(dòng)釋放已持有的鎖。

5.2 錯(cuò)誤的鎖對(duì)象:導(dǎo)致同步失效

問(wèn)題描述

在使用synchronized修飾代碼塊時(shí),如果鎖對(duì)象選擇不當(dāng)(如使用可變對(duì)象、字符串常量池中的對(duì)象等),可能會(huì)導(dǎo)致同步失效,無(wú)法保證線程安全。

常見(jiàn)錯(cuò)誤場(chǎng)景1:使用可變對(duì)象作為鎖對(duì)象

public class BadLockObjectDemo1 {
    // 可變鎖對(duì)象:value可能被修改
    private String lock = "lock";
    public void updateLockAndSync() {
        // 先修改鎖對(duì)象的值(導(dǎo)致鎖對(duì)象引用改變)
        lock = "newLock";
        // 此時(shí)的鎖對(duì)象是"newLock",而非最初的"lock"
        synchronized (lock) {
            System.out.println(Thread.currentThread().getName() + " 執(zhí)行同步代碼");
        }
    }
    public static void main(String[] args) {
        BadLockObjectDemo1 demo = new BadLockObjectDemo1();
        // 線程1和線程2可能使用不同的鎖對(duì)象,導(dǎo)致同步失效
        new Thread(demo::updateLockAndSync, "線程1").start();
        new Thread(demo::updateLockAndSync, "線程2").start();
    }
}

問(wèn)題原因

鎖對(duì)象lock是一個(gè)可變的字符串引用,當(dāng)lock = "newLock"執(zhí)行后,鎖對(duì)象的引用發(fā)生了改變。此時(shí),線程 1 和線程 2 可能使用不同的鎖對(duì)象(線程 1 使用"lock",線程 2 使用"newLock"),導(dǎo)致同步代碼塊無(wú)法實(shí)現(xiàn)同步效果。

解決方案

使用不可變對(duì)象作為鎖對(duì)象,如private final Object lock = new Object();。final關(guān)鍵字確保鎖對(duì)象的引用不會(huì)被修改,從而保證同步的有效性。

常見(jiàn)錯(cuò)誤場(chǎng)景2:使用字符串常量池中的對(duì)象作為鎖對(duì)象

public class BadLockObjectDemo2 {
    // 使用字符串常量作為鎖對(duì)象(存在于字符串常量池中)
    private final String lock = "LOCK";
    public void syncWithStringLock() {
        synchronized (lock) {
            System.out.println(Thread.currentThread().getName() + " 執(zhí)行同步代碼");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    public static void main(String[] args) {
        BadLockObjectDemo2 demo1 = new BadLockObjectDemo2();
        BadLockObjectDemo2 demo2 = new BadLockObjectDemo2();
        // demo1和demo2的lock對(duì)象引用的是字符串常量池中的同一個(gè)"LOCK"對(duì)象
        // 線程1和線程2會(huì)競(jìng)爭(zhēng)同一把鎖,導(dǎo)致本應(yīng)獨(dú)立的實(shí)例同步代碼塊相互阻塞
        new Thread(() -> demo1.syncWithStringLock(), "線程1").start();
        new Thread(() -> demo2.syncWithStringLock(), "線程2").start();
    }
}

問(wèn)題原因

在Java中,字符串常量會(huì)被存儲(chǔ)在字符串常量池中,相同內(nèi)容的字符串常量會(huì)指向同一個(gè)對(duì)象。上述代碼中,demo1demo2lock變量都指向常量池中的同一個(gè)"LOCK"對(duì)象,導(dǎo)致兩個(gè)不同實(shí)例的同步代碼塊共享同一把鎖。當(dāng)線程1執(zhí)行demo1syncWithStringLock方法時(shí),會(huì)持有該鎖,線程2執(zhí)行demo2的同名方法時(shí)會(huì)被阻塞,違背了"不同實(shí)例的同步代碼塊應(yīng)相互獨(dú)立"的預(yù)期。

解決方案

避免使用字符串常量或基本類型包裝類(如Integer,其緩存機(jī)制也會(huì)導(dǎo)致類似問(wèn)題)作為鎖對(duì)象,改用new Object()創(chuàng)建獨(dú)立的鎖對(duì)象,或使用當(dāng)前實(shí)例(this)作為鎖對(duì)象(確保不同實(shí)例的鎖相互獨(dú)立)。

5.3 鎖競(jìng)爭(zhēng)導(dǎo)致的性能瓶頸

問(wèn)題描述

在高并發(fā)場(chǎng)景下,如果多個(gè)線程頻繁競(jìng)爭(zhēng)同一把synchronized鎖,會(huì)導(dǎo)致大量線程阻塞和喚醒,引發(fā)用戶態(tài)與內(nèi)核態(tài)的切換,增加系統(tǒng)開(kāi)銷,最終導(dǎo)致程序性能下降,出現(xiàn)響應(yīng)延遲、吞吐量降低等問(wèn)題。

典型場(chǎng)景

在秒殺系統(tǒng)中,所有請(qǐng)求線程都需要競(jìng)爭(zhēng)同一把鎖來(lái)修改庫(kù)存變量,此時(shí)鎖競(jìng)爭(zhēng)會(huì)非常激烈,成為系統(tǒng)的性能瓶頸。

問(wèn)題分析

當(dāng)鎖競(jìng)爭(zhēng)激烈時(shí),synchronized的鎖狀態(tài)會(huì)升級(jí)為重量級(jí)鎖,線程會(huì)進(jìn)入內(nèi)核態(tài)等待隊(duì)列。每次線程的阻塞和喚醒都需要切換內(nèi)核態(tài),而內(nèi)核態(tài)切換的開(kāi)銷遠(yuǎn)大于用戶態(tài)操作,大量的內(nèi)核態(tài)切換會(huì)嚴(yán)重消耗CPU資源,導(dǎo)致程序處理請(qǐng)求的效率降低。

解決方案

  • 減少鎖競(jìng)爭(zhēng)頻率
    • 例如,將秒殺庫(kù)存按商品ID分段,每個(gè)分段使用獨(dú)立的鎖,避免所有線程競(jìng)爭(zhēng)同一把鎖。
    • 通過(guò)減小鎖粒度(如分段鎖)
    • 使用無(wú)鎖數(shù)據(jù)結(jié)構(gòu)(如AtomicInteger
  • 使用樂(lè)觀鎖替代悲觀鎖
    • synchronized是悲觀鎖,默認(rèn)認(rèn)為線程會(huì)存在激烈競(jìng)爭(zhēng),每次獲取鎖都會(huì)阻塞其他線程。
    • 樂(lè)觀鎖(如基于CASAtomic類、版本號(hào)機(jī)制)默認(rèn)認(rèn)為線程競(jìng)爭(zhēng)較少,通過(guò)重試機(jī)制實(shí)現(xiàn)同步,避免線程阻塞。
// 使用AtomicInteger(樂(lè)觀鎖)替代synchronized修改庫(kù)存
public class SeckillService {
    // 無(wú)鎖的原子類,避免鎖競(jìng)爭(zhēng)
    private AtomicInteger stock = new AtomicInteger(1000);
    public boolean seckill() {
        // CAS操作:如果當(dāng)前庫(kù)存大于0,就將庫(kù)存減1
        int currentStock;
        do {
            currentStock = stock.get();
            if (currentStock <= 0) {
                return false;
            }
        } while (!stock.compareAndSet(currentStock, currentStock - 1));
        return true;
    }
}
  • 讀寫分離
    • 對(duì)于讀多寫少的場(chǎng)景,使用ReadWriteLockStampedLock
    • 允許多個(gè)線程同時(shí)讀取數(shù)據(jù),但寫操作需要獨(dú)占鎖
  • 鎖粗化與鎖消除
    • 鎖粗化:將多個(gè)連續(xù)的鎖操作合并為一個(gè)更大的鎖操作
    • 鎖消除:JVM在編譯時(shí)進(jìn)行逃逸分析,消除不必要的鎖
  • 使用并發(fā)容器
    • ConcurrentHashMap、CopyOnWriteArrayList
    • 這些容器內(nèi)部已經(jīng)實(shí)現(xiàn)了高效的并發(fā)控制機(jī)制

六、synchronized 與 Lock 接口的對(duì)比

在 Java 并發(fā)編程中,除了synchronized關(guān)鍵字,java.util.concurrent.locks.Lock接口也是常用的同步手段。Lock接口提供了比synchronized更靈活的同步控制能力,但兩者在使用方式、功能特性和性能上存在差異。下面從多個(gè)維度對(duì)比兩者的區(qū)別,幫助開(kāi)發(fā)者根據(jù)業(yè)務(wù)場(chǎng)景選擇合適的同步方式。

6.1 功能特性對(duì)比

synchronized 關(guān)鍵字
  • 獲取鎖方式
    • 隱式獲?。哼M(jìn)入同步代碼塊/方法時(shí)自動(dòng)獲取鎖,退出時(shí)自動(dòng)釋放鎖
    • 示例:synchronized(this) { ... }public synchronized void method() { ... }
  • 可中斷性
    • 不可中斷:線程獲取鎖時(shí)會(huì)一直阻塞,無(wú)法被中斷
    • 場(chǎng)景:在死鎖情況下無(wú)法通過(guò)中斷恢復(fù)
  • 超時(shí)獲取鎖
    • 不支持:線程會(huì)一直阻塞,直到獲取到鎖
    • 風(fēng)險(xiǎn):可能導(dǎo)致線程永久阻塞
  • 公平鎖支持
    • 非公平鎖:默認(rèn)情況下,線程獲取鎖的順序不遵循請(qǐng)求順序
    • JVM優(yōu)化:JDK 1.6后引入偏向鎖、輕量級(jí)鎖優(yōu)化
  • 條件變量支持
    • 單一條件變量:通過(guò)wait()notify()、notifyAll()實(shí)現(xiàn)
    • 限制:一個(gè)鎖對(duì)象只能對(duì)應(yīng)一個(gè)條件隊(duì)列
Lock 接口(以 ReentrantLock 為例)
  • 獲取鎖方式
    • 顯式獲取:通過(guò)lock()方法獲取鎖
    • 必須通過(guò)unlock()方法手動(dòng)釋放鎖(通常在finally塊中)
  • 示例:
lock.lock();
try {
    // 臨界區(qū)代碼
} finally {
    lock.unlock();
}
  • 可中斷性
    • 可中斷:支持lockInterruptibly()方法
    • 場(chǎng)景:可以響應(yīng)Thread.interrupt()中斷等待
  • 超時(shí)獲取鎖
    • 支持:通過(guò)tryLock(long timeout, TimeUnit unit)方法
    • 優(yōu)勢(shì):避免線程永久阻塞,提高系統(tǒng)健壯性
  • 公平鎖支持
    • 可配置:通過(guò)構(gòu)造函數(shù)ReentrantLock(boolean fair)配置
    • 公平鎖(fair=true):遵循FIFO原則
    • 非公平鎖(fair=false):默認(rèn)配置,性能更好
  • 條件變量支持
    • 多個(gè)條件變量:通過(guò)newCondition()創(chuàng)建多個(gè)Condition對(duì)象
    • 應(yīng)用:可以實(shí)現(xiàn)更復(fù)雜的線程間協(xié)調(diào)
    • 示例:
Condition notEmpty = lock.newCondition();
Condition notFull = lock.newCondition();

6.2 代碼示例對(duì)比

6.2.1 synchronized 實(shí)現(xiàn)同步

public class SynchronizedExample {
    private final Object lock = new Object(); // 鎖對(duì)象
    private int count = 0; // 共享變量
    // 隱式獲取和釋放鎖
    public void increment() {
        synchronized (lock) { // 同步代碼塊
            count++; // 線程安全操作
        }
    }
    public int getCount() {
        synchronized (lock) { // 同步代碼塊
            return count; // 線程安全讀取
        }
    }
    // 同步方法示例
    public synchronized void syncMethod() {
        // 方法體自動(dòng)同步
    }
}

6.2.2 Lock 接口實(shí)現(xiàn)同步

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LockExample {
    private final Lock lock = new ReentrantLock(); // 顯式創(chuàng)建鎖對(duì)象
    private int count = 0; // 共享變量
    public void increment() {
        // 顯式獲取鎖
        lock.lock(); // 可能阻塞
        try {
            // 業(yè)務(wù)邏輯:修改共享變量
            count++;
        } finally {
            // 必須在finally中釋放鎖,避免異常導(dǎo)致鎖泄漏
            lock.unlock();
        }
    }
    // 帶超時(shí)的嘗試獲取鎖
    public boolean tryIncrement(long timeout, TimeUnit unit) 
        throws InterruptedException {
        if (lock.tryLock(timeout, unit)) { // 嘗試獲取鎖
            try {
                count++;
                return true;
            } finally {
                lock.unlock();
            }
        }
        return false; // 獲取鎖失敗
    }
    public int getCount() {
        lock.lock();
        try {
            return count;
        } finally {
            lock.unlock();
        }
    }
}

6.3 適用場(chǎng)景選擇

優(yōu)先選擇 synchronized 的場(chǎng)景:

  • 簡(jiǎn)單同步需求
    • 單一線程安全的方法或代碼塊
    • 不需要復(fù)雜的同步控制(如中斷、超時(shí))
  • 代碼可維護(hù)性
    • 希望代碼簡(jiǎn)潔易讀
    • 減少手動(dòng)管理鎖的風(fēng)險(xiǎn)(如鎖泄漏)
  • 性能考慮
    • 低并發(fā)或中等并發(fā)場(chǎng)景
    • JVM對(duì)synchronized的優(yōu)化(偏向鎖、輕量級(jí)鎖)能帶來(lái)較好性能
  • 快速開(kāi)發(fā)
    • 原型開(kāi)發(fā)或?qū)π阅芤蟛桓叩膱?chǎng)景

選擇 Lock 接口的場(chǎng)景:

  • 高級(jí)同步需求
    • 需要中斷正在等待鎖的線程
    • 示例:處理超時(shí)任務(wù)時(shí)中斷等待
  • 超時(shí)控制
    • 需要設(shè)置超時(shí)時(shí)間,避免線程永久阻塞
    • 應(yīng)用場(chǎng)景:網(wǎng)絡(luò)請(qǐng)求超時(shí)控制
  • 公平性要求
    • 需要公平鎖,確保線程按請(qǐng)求順序獲取鎖
    • 應(yīng)用場(chǎng)景:對(duì)資源分配順序有嚴(yán)格要求的系統(tǒng)
  • 復(fù)雜條件控制
    • 需要多個(gè)條件變量實(shí)現(xiàn)精細(xì)控制
    • 典型應(yīng)用:生產(chǎn)者-消費(fèi)者模型中分別喚醒生產(chǎn)者和消費(fèi)者
  • 性能關(guān)鍵場(chǎng)景
    • 高并發(fā)場(chǎng)景下需要更細(xì)粒度的控制
    • 需要嘗試獲取鎖而不阻塞(tryLock)
  • 鎖的可擴(kuò)展性
    • 未來(lái)可能需要擴(kuò)展鎖的功能
    • Lock接口提供了更多擴(kuò)展可能性

七、常用 JVM 參數(shù)與調(diào)試工具

7.1 與 synchronized 相關(guān)的 JVM 參數(shù)

詳細(xì)參數(shù)說(shuō)明與應(yīng)用場(chǎng)景

JVM 參數(shù)作用默認(rèn)值適用場(chǎng)景注意事項(xiàng)
-XX:+UseBiasedLocking開(kāi)啟偏向鎖優(yōu)化JDK 1.6~1.14 默認(rèn)開(kāi)啟(JDK 15 后廢棄偏向鎖)適用于單線程重復(fù)訪問(wèn)同步塊的場(chǎng)景JDK 15+ 已廢棄,在競(jìng)爭(zhēng)激烈場(chǎng)景下可能反而降低性能
-XX:-UseBiasedLocking關(guān)閉偏向鎖優(yōu)化-多線程競(jìng)爭(zhēng)激烈場(chǎng)景可減少鎖升級(jí)開(kāi)銷,適用于高并發(fā)環(huán)境
-XX:BiasedLockingStartupDelay偏向鎖啟動(dòng)延遲時(shí)間(毫秒)4000ms(JDK 1.6 及之后)需要延遲啟用偏向鎖的特殊場(chǎng)景設(shè)置0表示立即啟用,常用于性能測(cè)試
-XX:-EliminateLocks關(guān)閉鎖消除優(yōu)化默認(rèn)開(kāi)啟調(diào)試鎖行為會(huì)禁用JVM的逃逸分析優(yōu)化,影響性能
-XX:-EliminateAllocations關(guān)閉標(biāo)量替換優(yōu)化(影響鎖消除)默認(rèn)開(kāi)啟調(diào)試逃逸分析相關(guān)行為關(guān)閉后會(huì)影響鎖消除效果
-XX:PreBlockSpin輕量級(jí)鎖自旋次數(shù)JDK 1.6 后由 JVM 動(dòng)態(tài)調(diào)整,無(wú)需手動(dòng)設(shè)置歷史版本調(diào)優(yōu)現(xiàn)代JVM已實(shí)現(xiàn)自適應(yīng)自旋,不建議手動(dòng)設(shè)置

典型應(yīng)用場(chǎng)景示例

  • 對(duì)于Web服務(wù)應(yīng)用,建議在JDK 15以下版本使用-XX:+UseBiasedLocking以獲得更好的單線程性能
  • 在高并發(fā)交易系統(tǒng)中,可以嘗試-XX:-UseBiasedLocking來(lái)避免偏向鎖的撤銷開(kāi)銷
  • 調(diào)試死鎖問(wèn)題時(shí),可以臨時(shí)關(guān)閉鎖消除-XX:-EliminateLocks來(lái)觀察真實(shí)鎖競(jìng)爭(zhēng)情況

7.2 調(diào)試 synchronized 的工具

7.2.1 jstack 工具詳解

功能:用于打印Java進(jìn)程的線程堆棧信息,可查看線程的鎖持有情況和等待情況,幫助定位死鎖。

使用方式

  1. 獲取Java進(jìn)程ID:jps -l
  2. 生成線程dump:jstack -l <pid> > thread_dump.log
  3. 分析dump文件中的鎖信息:
    • 查找BLOCKED狀態(tài)的線程
    • 查看waiting to lock <0x0000000712345678>信息
    • 對(duì)應(yīng)查找locked <0x0000000712345678>的線程

示例輸出分析

"Thread-1" #12 prio=5 os_prio=0 tid=0x00007f8a3418b000 nid=0x1a3e waiting for monitor entry [0x00007f8a2bdfe000]
   java.lang.Thread.State: BLOCKED (on object monitor)
    at com.example.DeadLock.run(DeadLock.java:20)
    - waiting to lock <0x0000000712345678> (a java.lang.Object)
    - locked <0x0000000712345690> (a java.lang.Object)

"Thread-2" #13 prio=5 os_prio=0 tid=0x00007f8a3418d800 nid=0x1a3f waiting for monitor entry [0x00007f8a2bcfe000]
   java.lang.Thread.State: BLOCKED (on object monitor)
    at com.example.DeadLock.run(DeadLock.java:20)
    - waiting to lock <0x0000000712345690> (a java.lang.Object)
    - locked <0x0000000712345678> (a java.lang.Object)

7.2.2 jconsole 使用指南

功能特點(diǎn)

  • 圖形化界面,直觀易用
  • 實(shí)時(shí)監(jiān)控線程狀態(tài)
  • 可視化展示鎖競(jìng)爭(zhēng)情況

操作步驟

  1. 啟動(dòng)jconsole:jconsole
  2. 連接目標(biāo)Java進(jìn)程
  3. 切換到"線程"選項(xiàng)卡
  4. 點(diǎn)擊"同步監(jiān)視器"按鈕查看鎖信息
  5. 雙擊線程可查看詳細(xì)堆棧

適用場(chǎng)景

  • 開(kāi)發(fā)環(huán)境實(shí)時(shí)監(jiān)控
  • 演示和教學(xué)場(chǎng)景
  • 快速驗(yàn)證鎖行為

7.2.3 VisualVM 高級(jí)功能

核心功能

  • 線程分析:
    • 實(shí)時(shí)線程狀態(tài)監(jiān)控
    • 線程dump生成與分析
    • 死鎖自動(dòng)檢測(cè)
  • 性能分析:
    • CPU和內(nèi)存分析
    • 方法級(jí)熱點(diǎn)分析
    • 鎖競(jìng)爭(zhēng)統(tǒng)計(jì)

使用流程

graph TD
    A[啟動(dòng)VisualVM] --> B[連接目標(biāo)JVM]
    B --> C[選擇"線程"標(biāo)簽]
    C --> D[查看線程狀態(tài)圖]
    D --> E[生成線程dump]
    E --> F[分析鎖依賴關(guān)系]

插件擴(kuò)展

  • Threads Inspector:增強(qiáng)線程分析能力
  • Deadlock Detector:自動(dòng)死鎖檢測(cè)
  • Visual GC:可視化GC分析

7.2.4 Arthas 診斷實(shí)戰(zhàn)

  • 常用命令詳解
  • thread命令家族:
    • thread:列出所有線程
    • thread -b:檢測(cè)死鎖(找出阻塞線程及其鎖持有者)
    • thread <id>:查看指定線程堆棧
    • thread --state BLOCKED:過(guò)濾阻塞狀態(tài)線程
  • monitor命令:
    • 監(jiān)控方法級(jí)鎖競(jìng)爭(zhēng):monitor -c 5 com.example.Service methodName
  • 輸出字段說(shuō)明:
    • timestamp:時(shí)間戳
    • class:類名
    • method:方法名
    • total:調(diào)用次數(shù)
    • success:成功次數(shù)
    • fail:失敗次數(shù)
    • avg-rt:平均響應(yīng)時(shí)間
    • fail-rate:失敗率
  • 高級(jí)診斷流程:
# 1. 查看阻塞線程
thread -b
# 2. 監(jiān)控可疑方法的鎖競(jìng)爭(zhēng)
monitor -c 5 com.example.Controller doPost
# 3. 觀察特定鎖對(duì)象的持有情況
watch java.lang.Object toString '{params[0], returnObj}' -x 2 -b -s com.example.LockHolder.monitor

典型應(yīng)用場(chǎng)景

  • 生產(chǎn)環(huán)境快速診斷鎖問(wèn)題
  • 無(wú)法重現(xiàn)的偶發(fā)死鎖分析
  • 性能瓶頸定位(鎖競(jìng)爭(zhēng))

到此這篇關(guān)于深入理解 Java 中的 synchronized 關(guān)鍵字的文章就介紹到這了,更多相關(guān)Java synchronized 關(guān)鍵字內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java使用抽象工廠模式實(shí)現(xiàn)的肯德基消費(fèi)案例詳解

    Java使用抽象工廠模式實(shí)現(xiàn)的肯德基消費(fèi)案例詳解

    這篇文章主要介紹了Java使用抽象工廠模式實(shí)現(xiàn)的肯德基消費(fèi)案例,較為詳細(xì)的分析了抽象工廠模式的定義、原理并結(jié)合實(shí)例形式分析了Java使用抽象工廠模式實(shí)現(xiàn)肯德基消費(fèi)案例的步驟與相關(guān)操作技巧,需要的朋友可以參考下
    2018-05-05
  • java 解決Eclipse掛掉問(wèn)題的方法

    java 解決Eclipse掛掉問(wèn)題的方法

    本篇文章是對(duì)在java中解決Eclipse掛掉問(wèn)題的方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • SpringBoot中的PUT和Delete請(qǐng)求使用

    SpringBoot中的PUT和Delete請(qǐng)求使用

    這篇文章主要介紹了SpringBoot中的PUT和Delete請(qǐng)求使用,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-07-07
  • 詳解Java中如何使用日志庫(kù)在代碼中添加日志

    詳解Java中如何使用日志庫(kù)在代碼中添加日志

    這篇文章主要為大家介紹了Java中如何使用日志庫(kù)在代碼中添加日志詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-07-07
  • Spring MVC 基于URL的映射規(guī)則(注解版)

    Spring MVC 基于URL的映射規(guī)則(注解版)

    這篇文章主要介紹了Spring MVC 基于URL的映射規(guī)則(注解版) ,詳細(xì)的介紹了幾種方式,有興趣的可以了解一下
    2017-05-05
  • springboot報(bào)錯(cuò)Invalid?bound?statement?(not?found)的解決

    springboot報(bào)錯(cuò)Invalid?bound?statement?(not?found)的解決

    本文主要介紹了springboot報(bào)錯(cuò)Invalid?bound?statement?(not?found)的解決,遇到這種問(wèn)題通常是沒(méi)有配置好配置文件,下面就來(lái)具體介紹一下解決方法,感興趣的可以了解一下
    2025-03-03
  • SpringBoot系列教程之防重放與操作冪等

    SpringBoot系列教程之防重放與操作冪等

    同一條數(shù)據(jù)被用戶點(diǎn)擊了多次,導(dǎo)致數(shù)據(jù)冗余,需要防止弱網(wǎng)絡(luò)等環(huán)境下的重復(fù)點(diǎn)擊,下面這篇文章主要給大家介紹了關(guān)于SpringBoot系列教程之防重放與操作冪等的相關(guān)資料,需要的朋友可以參考下
    2022-04-04
  • java面試常見(jiàn)問(wèn)題---ConcurrentHashMap

    java面試常見(jiàn)問(wèn)題---ConcurrentHashMap

    ConcurrentHashMap是由Segment數(shù)組結(jié)構(gòu)和HashEntry數(shù)組結(jié)構(gòu)組成。Segment的結(jié)構(gòu)和HashMap類似,是一種數(shù)組和鏈表結(jié)構(gòu),今天給大家普及java面試常見(jiàn)問(wèn)題---ConcurrentHashMap知識(shí),一起看看吧
    2021-06-06
  • springboot 多環(huán)境切換的方法

    springboot 多環(huán)境切換的方法

    這篇文章主要介紹了springboot 多環(huán)境切換的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • Spring Boot 集成Mybatis實(shí)現(xiàn)主從(多數(shù)據(jù)源)分離方案示例

    Spring Boot 集成Mybatis實(shí)現(xiàn)主從(多數(shù)據(jù)源)分離方案示例

    本篇文章主要介紹了Spring Boot 集成Mybatis實(shí)現(xiàn)主從(多數(shù)據(jù)源)分離方案實(shí)例,具有一定的參考價(jià)值,有興趣的可以了解一下。
    2017-03-03

最新評(píng)論

阿拉善右旗| 锡林郭勒盟| 青岛市| 富顺县| 高安市| 延川县| 景谷| 历史| 东台市| 二连浩特市| 拉萨市| 县级市| 年辖:市辖区| 澳门| 西林县| 文登市| 西乌珠穆沁旗| 临沧市| 长沙县| 宜黄县| 尚义县| 什邡市| 辽源市| 柏乡县| 青海省| 靖西县| 汾西县| 富阳市| 贺兰县| 海宁市| 西安市| 伊吾县| 岱山县| 洪雅县| 鹰潭市| 平安县| 衢州市| 陆河县| 泸定县| 宜良县| 九龙城区|