1. 程式人生 > >Java開發之執行緒同步造成的執行緒死鎖

Java開發之執行緒同步造成的執行緒死鎖

案例解析:

兩個人面對面過獨木橋,甲和乙都已經在橋上走了一段距離,即佔用了橋的資源,甲如果想通過獨木橋的話,乙必須退出橋面讓出橋的資源,讓甲通過,但是乙不服,為什麼讓我先退出去,我還想先過去呢,於是就僵持不下,導致誰也過不了橋,這就是死鎖。

死鎖產生情況解析:

1.互斥條件(只有一個冠軍):一個資源每次只能被一個程序使用。獨木橋每次只能通過一個人。

2.請求與保持條件(互不相讓):一個程序因請求資源而阻塞時,對已獲得的資源保持不放。乙不退出橋面,甲也不退出橋面。

3.不剝奪條件(平等優先順序): 程序已獲得的資源,在未使用完之前,不能強行剝奪。甲不能強制乙退出橋面,乙也不能強制甲退出橋面。

4.迴圈等待條件(敵退我進,敵進我退):若干程序之間形成一種頭尾相接的迴圈等待資源關係。如果乙不退出橋面,甲不能通過,甲不退出橋面,乙不能通過。

程式碼演示:

package deadlock;

public class DeadlockTest {

    public static void main(String[] args) {
        String res1 = new String("左獨木橋");
        String res2 = new String("右獨木橋");

        new Thread(new Lock(res1, res2), "過橋者甲").start();
        new Thread(new Lock(res2, res1), "過橋者乙").start();
    }
}

class Lock implements Runnable {

    private String str1;
    private String str2;

    public Lock(String str1, String str2) {
        super();
        this.str1 = str1;
        this.str2 = str2;
    }

    @Override
    public void run() {
        try {
            System.out.println(Thread.currentThread().getName() + "  執行");
            synchronized (str1) {
                System.out.println(Thread.currentThread().getName() + "  鎖住  "
                        + str1);
                Thread.sleep(1000);
                synchronized (str2) {
                    // 執行不到這裡
                    System.out.println(Thread.currentThread().getName()
                            + " 鎖住" + str2);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

結果:
在這裡插入圖片描述
原因分析:巢狀的同步語句時造成死鎖的原因,對方沒有讓出己方的過橋資源,兩者都不可以獲得對方的資源。

避免死鎖:

1.避免一個執行緒同時獲取多個鎖。
2.避免在一個資源內佔用多個 資源,儘量保證每個鎖只佔用一個資源。
3.嘗試使用定時鎖,使用tryLock(timeout)來代替使用內部鎖機制。
4.對於資料庫鎖,加鎖和解鎖必須在一個數據庫連線裡,否則會出現解鎖失敗的情況。
5.避免同步巢狀的發生