java中如何造成死鎖的?以及如何解決死鎖

2021-09-13 03:03:59 字數 3383 閱讀 7680

造成死鎖的原因:

1.在乙個**塊中同時獲得多個鎖,導致多個執行緒同時執行**時,獲取鎖之間相互依賴,從而導致鎖「抱死」。例如,t1執行緒首先獲得a鎖,再獲得b鎖,t2執行緒先獲得b鎖,再獲得a鎖,當t1獲得a鎖的同時,t2獲得了b鎖的使用權,此時t1無法獲取b鎖,t2也無法獲得a鎖,執行緒一直等待,這就叫鎖「抱死」。

2.在同步**塊中呼叫了外部的同步方法(常見)

下面我將結合實際情況分析賬戶轉賬時,發生死鎖的**示例。

首先建乙個account類,包括賬戶id,賬戶名稱,賬戶餘額。

public class account 

public account(int id,string name)

public int compareto(double money)else if(balance == money)else }

public void in(double money)

public void out(double money)

/*** @return the accname

*/public string getaccname()

/*** @param accname the accname to set

*/public void setaccname(string accname)

/*** @return the balance

*/public double getbalance()

/*** @param balance the balance to set

*/public void setbalance(double balance)

/*** @return the id

*/public int getid()

/*** @param id the id to set

*/public void setid(int id)

}

實現轉賬的方法:

/**

* 造成死鎖的示例:通過synchronized同步**塊

* @param a

* @param b

* @param money

* @throws exception

*/public static void transfermoney(account a,account b,double money) throws exception

synchronized(a)

} }

測試方法:

public static void main(string args)  catch (exception e) 

}}).start();

new thread(new runnable() catch (exception e)

}}).start();

}

測試結果:

問題的原因開頭已經提到了,zhangsan賬戶向lis賬戶轉賬首先獲取了zhangsan的物件鎖,lis同時向zhangsan轉賬獲得了lisi的物件鎖,此時zhangsan無法獲得zhangsan的物件鎖,lisi無法獲取到zhangsan的物件鎖,從而導致死鎖。那麼問題原因知道了,如何解決呢?

通過hashcode給物件鎖排序,使得每次獲取鎖的順序是一致的。這裡物件的hashcode一般情況下是不一樣的,如果為了保險起見可以使用物件的唯一id進行排序也是可以的。

/**方法一

* 解決死鎖的方法:根據hashcode給鎖排序,按照乙個指定的順序加鎖

* @param a

* @param b

* @param money

* @throws exception

*/public static void solvedeadlock1(account a,account b,double money) throws exception

if(a.hashcode()執行結果:

轉賬方法修改為同步方法:

public synchronized void in(double money)

/**

* 造成死鎖的示例:通過synchronized同步方法

* @param a

* @param b

* @param money

* @throws exception

*/public static void transfermoney1(account a,account b,double money) throws exception

synchronized(a)

}

測試結果:

原因和第一種是一樣的,只是將同步**塊換成了同步方法,我們會發現zhangsan和lisi的賬戶中都少了10元,所以請記住一點:避免在同步**塊中呼叫外部的同步方法。

解決方法是盡量讓原子操作的範圍最小化。

實際上在轉賬過程中變數就是餘額balance,而且balance是在in和out方法裡計算的,所以將轉入in方法和轉出out方法都寫為同步方法。

public synchronized void in(double money)

public synchronized void out(double money)

/**

* 解決死鎖的方法:將原子操作的範圍最小化,避免在同步**塊中呼叫外部的同步方法

* @param a

* @param b

* @param money

* @throws exception

*/public static void solvedeadlock3(account a,account b,double money) throws exception

a.out(money);

b.in(money);

}

測試結果:

總結1.避免在同步**塊中呼叫外部的同步方法。

2.在巢狀多層synchronized同塊中,對鎖進行排序,使得每次獲取鎖的順序是一致的。

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

兩個人面對面過獨木橋,甲和乙都已經在橋上走了一段距離,即占用了橋的資源,甲如果想通過獨木橋的話,乙必須退出橋面讓出橋的資源,讓甲通過,但是乙不服,為什麼讓我先退出去,我還想先過去呢,於是就僵持不下,導致誰也過不了橋,這就是死鎖。1.互斥條件 只有乙個冠軍 乙個資源每次只能被乙個程序使用。獨木橋每次只...

java中的死鎖

定義 兩個或者兩個以上的執行緒在執行的過程中,因資源競爭造成的相互等待,無法繼續執行下去。造成死鎖的原因 系統資源的競爭 執行緒推進順序不當等造成 產生死鎖的四個必要條件 互斥條件 對獲取到的資源具有排它性 請求和保持條件 因請求被占用的資源而阻塞時,對已獲得到資源保持不放 不可剝奪條件 其他程序或...

死鎖發生的條件以及如何避免死鎖

死鎖 死鎖,它是作業系統或軟體執行的一種狀態 在多工下,當乙個或多個程序等待系統資源而資源又被系統本身 或其它程序占用時,就形成了死鎖。死鎖發生的最常見形式是兩個或多個執行緒等待被另乙個執行緒占用的資源 如果兩個順序同時發生,執行緒1將永遠無法獲得鎖b,因為鎖b被執行緒2占有。同時執行緒2也永遠無法...