切換語言為:簡體
發生死鎖的四個條件以及解決方法

發生死鎖的四個條件以及解決方法

  • 爱糖宝
  • 2024-07-31
  • 2085
  • 0
  • 0

死鎖(Dead Lock)指的是兩個或兩個以上的運算單元(程序、執行緒或協程),互相持有對方所需的資源,導致它們都無法向前推進,從而導致永久阻塞的問題就是死鎖。

比如執行緒 1 擁有了鎖 A 的情況下試圖獲取鎖 B,而執行緒 2 又在擁有了鎖 B 的情況下試圖獲取鎖 A,這樣雙方就進入相互阻塞等待的情況,如下圖所示:

發生死鎖的四個條件以及解決方法發生死鎖的四個條件以及解決方法

死鎖的程式碼實現如下:

public class DeadlockDemo {
    public static void main(String[] args) {
        Object lock1 = new Object();
        Object lock2 = new Object();

        Thread thread1 = new Thread(() -> {
            synchronized (lock1) {
                System.out.println("Thread 1 acquired lock1");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                synchronized (lock2) {
                    System.out.println("Thread 1 acquired lock2");
                }
            }
        });

        Thread thread2 = new Thread(() -> {
            synchronized (lock2) {
                System.out.println("Thread 2 acquired lock2");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                synchronized (lock1) {
                    System.out.println("Thread 2 acquired lock1");
                }
            }
        });

        thread1.start();
        thread2.start();
    }}

在上面的示例中,我們建立了兩個鎖 lock1 和 lock2,並在兩個執行緒中分別獲取這兩個鎖,但是獲取的順序不同。當 thread1 獲取 lock1 後,它會在持有鎖 lock1 的情況下嘗試獲取 lock2,而當 thread2 獲取 lock2 後,它會在持有鎖 lock2 的情況下嘗試獲取 lock1。 如果這兩個執行緒啟動後,thread1 先獲取 lock1 並且在獲取 lock2 之前休眠,那麼 thread2 就會獲取 lock2,然後在嘗試獲取 lock1 時被阻塞。此時,thread1 就會在獲取 lock2 時被阻塞。兩個執行緒都在等待對方釋放鎖,從而形成了死鎖。

# 死鎖 4 大條件

死鎖的產生需要滿足以下 4 個條件:

  1. 互斥條件:指運算單元(程序、執行緒或協程)對所分配到的資源具有排它性,也就是說在一段時間內某個鎖資源只能被一個運算單元所佔用。

  2. 請求和保持條件:指運算單元已經保持至少一個資源,但又提出了新的資源請求,而該資源已被其它運算單元佔有,此時請求運算單元阻塞,但又對自己已獲得的其它資源保持不放。

  3. 不可剝奪條件:指運算單元已獲得的資源,在未使用完之前,不能被剝奪。

  4. 環路等待條件:指在發生死鎖時,必然存在運算單元和資源的環形鏈,即運算單元正在等待另一個運算單元佔用的資源,而對方又在等待自己佔用的資源,從而造成環路等待的情況。

只有以上 4 個條件同時滿足,纔會造成死鎖。

# 解決死鎖

死鎖的常用解決方案有以下兩個:

  1. 按照順序加鎖:嘗試讓所有執行緒按照同一順序獲取鎖,從而避免死鎖。

  2. 設定獲取鎖的超時時間:嘗試獲取鎖的執行緒在規定時間內沒有獲取到鎖,就放棄獲取鎖,避免因為長時間等待鎖而引起的死鎖。

# 死鎖排查工具

有一些工具可以幫助排查死鎖問題,常見的工具有以下幾個:

  1. jstack:可以檢視 Java 應用程式的執行緒狀態和呼叫堆疊,可用於發現死鎖執行緒的狀態。

  2. jconsole 和 JVisualVM:這些是 Java 自帶的監視工具,可以用於監視執行緒、記憶體、CPU 使用率等資訊,從而幫助排查死鎖問題。

  3. Thread Dump Analyzer(TDA):是一個開源的執行緒轉儲分析器,可用於分析和診斷 Java 應用程式中的死鎖問題。

  4. Eclipse TPTP:是一個開源的效能測試工具平臺,其中包含了一個名為 Thread Profiler 的工具,可以用於跟蹤執行緒執行時的資訊,從而診斷死鎖問題。

0則評論

您的電子郵件等資訊不會被公開,以下所有項目均必填

OK! You can skip this field.