成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

三分鐘秒懂死鎖產生原因!

開發 前端
我們知道被synchronized修飾的代碼,當一個線程持有一個鎖,其它線程嘗試去獲取這個鎖未獲取到時,那么其它線程會進入阻塞狀態,直到線程釋放鎖才能再次擁有獲取鎖的條件。

一、簡介

在之前的文章中,我們介紹了synchronized同步鎖關鍵字的作用以及相關的用法,它能夠保證同一時刻最多只有一個線程執行修飾的代碼段,以實現線程安全執行的效果。

但是如果過度的使用synchronized等方式進行加鎖,程序可能會出現死鎖現象。

那什么是死鎖呢?它有什么危害?

我們知道被synchronized修飾的代碼,當一個線程持有一個鎖,其它線程嘗試去獲取這個鎖未獲取到時,那么其它線程會進入阻塞狀態,直到線程釋放鎖才能再次擁有獲取鎖的條件。假如線程 A 持有鎖 L 并且想獲取鎖 R,線程 B 持有鎖 R 并且想獲取鎖 L,那么這兩個線程將會永久等待下去,這種情況就是最簡單的死鎖現象。

如果程序出現了死鎖,會給系統功能帶來非常嚴重的問題,輕則導致程序響應時間變長,系統吞吐量變小;重則導致應用中的某一個功能直接失去響應能力無法提供服務,因此我們應該及時發現并避規這些問題。

當然發生死鎖的軟件應用,不僅限于 Java 程序,還有數據庫等,不同的是:數據庫系統中設計了死鎖的檢測以及從死鎖中恢復的機制,數據庫如果檢測到一組事務中發生了死鎖,將選擇一個犧牲者并放棄這個事務。

而 Java 虛擬機解決死鎖問題并沒有數據庫那么強大,在 Java 程序中,采用synchronized加鎖的代碼如果發生死鎖,兩個線程就不能再使用了,并且這兩個線程所在的同步代碼/代碼塊也無法再運行了,除非殺掉服務,然后重啟服務!

在實際的軟件項目開發過程中,死鎖其實是編程設計上的 bug,問題也比較隱晦,即使通過壓力測試也不一定能找到程序上的死鎖問題。死鎖的出現,往往是在高負載的情況下產生,這種場景下比較難定位。

二、死鎖復現

下面我們先來看一個比較經典的產生死鎖示例代碼。

public class DeadLock {

    private final Object right = new Object();

    private final Object left = new Object();

    /**
     * 加鎖順序從left -> right
     */
    public void leftRight() throws Exception {
        synchronized (left) {
            // 模擬某個業務操作耗時
            Thread.sleep(1000);
            synchronized (right) {
                System.out.println(Thread.currentThread().getName() + " left -> right lock.");
            }
        }
    }

    /**
     * 加鎖順序right -> left
     */
    public void rightLeft() throws Exception {
        synchronized (right) {
            // 模擬某個業務操作耗時
            Thread.sleep(1000);
            synchronized (left) {
                System.out.println(Thread.currentThread().getName() + " right -> left lock.");
            }
        }
    }
}
public class MyThreadA extends Thread {


    private DeadLock deadLock;

    public MyThreadA(DeadLock deadLock) {
        this.deadLock = deadLock;
    }

    @Override
    public void run() {
        try {
            deadLock.leftRight();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
public class MyThreadB extends Thread {


    private DeadLock deadLock;

    public MyThreadB(DeadLock deadLock) {
        this.deadLock = deadLock;
    }

    @Override
    public void run() {
        try {
            deadLock.rightLeft();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
public class MyThreadTest {

    public static void main(String[] args) {
        DeadLock deadLock = new DeadLock();

        MyThreadA threadA = new MyThreadA(deadLock);
        MyThreadB threadB = new MyThreadB(deadLock);
        threadA.start();
        threadB.start();
    }
}

運行測試類觀察控制臺,你會發現服務一直在運行,什么都沒有輸出,并且無法關閉,因為程序已經死鎖了!

圖片圖片

發生這個現象的原因,其實也很簡單。

1.線程 A 啟動之后,先獲取了left對象鎖,然后緊接著嘗試獲取right對象鎖,因為right對象鎖被其它線程占有,只能進入阻塞狀態

2.線程 B 啟動之后,先獲取了right對象鎖,然后緊接著嘗試獲取left對象鎖,因為left對象鎖被其它線程占有,只能進入阻塞狀態

3.兩個線程互相等待對方釋放鎖,程序進入永久等待狀態,因此都無法進入打印方法體

如何定位死鎖問題呢?

我們可以通過 Java 自帶的 jps 和 jstack 工具,查看 java 進程 id 和相關的線程堆棧信息。

定位過程如下!

2.1、通過 jps 獲得當前 Java 虛擬機進程的 pid

圖片圖片

左邊的是當前 Java 虛擬機進程 ID,后邊是進程名稱,其中MyThreadTest就是我們當前運行的測試類服務。

2.2、通過 jstack 查看進程中的線程信息

在 jstack 后面輸入對應的 java 進程 ID,然后回車即可查詢到進程中的線程情況,前面的部分,可以很清晰的看到,兩個線程都處于阻塞狀態,等待獲取對應的鎖。

圖片圖片

因為線程的信息比較多,直接滑倒最底部,可以看到 JVM 給出的死鎖報告信息。

圖片圖片

遇到這種情況,只能強制終止服務才能解除死鎖!

三、避免死鎖的方式

上面我們復現了死鎖的發生,總結下來你會發現死鎖的產生,總共有四個共同特點:

1.互斥使用,即當資源被一個線程占用時,別的線程不能使用

2.不可搶占,資源請求者不能強制從資源占有者手中搶奪資源,資源只能由占有者主動釋放

3.請求和保持,當資源請求者在請求其他資源的同時保持對原有資源的占有

4.循環等待,多個線程存在環路的鎖依賴關系而永遠等待下去,例如 T1 占有 T2 的資源,T2 占有 T3 的資源,T3 占有 T1 的資源,這種情況可能會形成一個等待環路

這四個特點是死鎖產生的必要條件,只要系統發生死鎖,這些條件必然成立,只要能破壞其中一條即可讓死鎖消失,當然條件一是基礎,不能被破壞。

理解了死鎖的原因,尤其是產生死鎖的四個必要條件,就可以最大可能地避免產生死鎖和解除死鎖。

在軟件編程中,我們如何避免死鎖呢?

關于死鎖的避免,主要有以下幾種方式:

1.盡可能使用無鎖編程,使用開放調用的編碼設計

2.設計時考慮清楚鎖的順序,盡量減少嵌在的加鎖交互數量

2.盡可能的縮小鎖的范圍,防止鎖住的資源過多引發阻塞

4.使用定時鎖,比如Lock類中的tryLock方法去嘗試獲取鎖,這個方法支持在指定時間內獲取鎖,如果等待超時會返回一個失敗信息,死鎖會自動解除。

對于死鎖的診斷,主要有以下幾種方式:

1.對代碼進行全局分析,找出代碼中什么地方會出現死鎖

2.通過線程轉儲(Thread Dump)信息來分析死鎖,比如 jstack、jvisualvm、jconsole 等工具

至于死鎖的解除,主要有以下幾種方式:

1.直接強制終止并重啟服務,如果代碼上的風險沒有消除,可能還會再次出現

2.采用定時鎖方案,雖然synchronized不具備這個功能,但是Lock類中的tryLock方法具備,實際編程中采用Lock中的超時機制進行加鎖,應用的比較多

責任編輯:武曉燕 來源: Java極客技術
相關推薦

2024-06-06 08:50:43

2024-08-05 09:05:44

2024-05-16 11:13:16

Helm工具release

2009-11-09 12:55:43

WCF事務

2024-12-18 10:24:59

代理技術JDK動態代理

2024-08-30 08:50:00

2022-02-17 09:24:11

TypeScript編程語言javaScrip

2024-01-16 07:46:14

FutureTask接口用法

2021-04-20 13:59:37

云計算

2023-12-27 08:15:47

Java虛擬線程

2020-06-30 10:45:28

Web開發工具

2013-06-28 14:30:26

棱鏡計劃棱鏡棱鏡監控項目

2021-12-17 07:47:37

IT風險框架

2020-06-29 07:42:20

邊緣計算云計算技術

2024-07-05 09:31:37

2023-12-04 18:13:03

GPU編程

2024-10-15 09:18:30

2009-11-05 16:04:19

Oracle用戶表

2024-01-12 07:38:38

AQS原理JUC

2021-02-03 14:31:53

人工智能人臉識別
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 久久成人亚洲 | 做a网站 | 全免费a级毛片免费看视频免 | 最新日韩av | 日韩精品视频一区二区三区 | 影音先锋男 | 欧美www在线观看 | 日本黄视频在线观看 | 久久精品成人一区 | 亚洲成人黄色 | 99久久国产综合精品麻豆 | 日本精品久久 | 亚洲精品一区二区三区四区高清 | 亚洲国产二区 | 久久久精品一区二区三区 | 99国产精品99久久久久久粉嫩 | 成人午夜视频在线观看 | 久久久国产亚洲精品 | 亚洲精品大全 | 国产精品免费av | 日韩最新网址 | 久久精品av | 日韩精品一区二区在线 | 国产精品美女久久久久久久网站 | 久久久爽爽爽美女图片 | 欧美成人精品激情在线观看 | 精品网站999www| 亚洲不卡 | 久久久久久成人 | 一级视频在线免费观看 | 黄色在线观看 | 国产精品片aa在线观看 | 久久男人天堂 | 亚洲精品在线免费观看视频 | 成人精品国产 | 91精品国产乱码久久久久久久 | 噜噜噜色网 | 91中文字幕在线观看 | 欧美成人精品欧美一级 | 久久久久国产精品午夜一区 | 日本三级黄视频 |