Java開發之執行緒同步造成的執行緒死鎖
阿新 • • 發佈:2018-11-26
案例解析:
兩個人面對面過獨木橋,甲和乙都已經在橋上走了一段距離,即佔用了橋的資源,甲如果想通過獨木橋的話,乙必須退出橋面讓出橋的資源,讓甲通過,但是乙不服,為什麼讓我先退出去,我還想先過去呢,於是就僵持不下,導致誰也過不了橋,這就是死鎖。
死鎖產生情況解析:
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.避免同步巢狀的發生