java如何避免程式死鎖

ckxllf發表於2019-09-26

  併發程式一旦死鎖,往往我們只能重啟應用。解決死鎖問題最好的辦法就是避免死鎖。

  死鎖發生的條件

  互斥,共享資源只能被一個執行緒佔用

  佔有且等待,執行緒 t1 已經取得共享資源 s1,嘗試獲取共享資源 s2 的時候,不釋放共享資源 s1

  不可搶佔,其他執行緒不能強行搶佔執行緒 t1 佔有的資源 s1

  迴圈等待,執行緒 t1 等待執行緒 t2 佔有的資源,執行緒 t2 等待執行緒 t1 佔有的資源

  避免死鎖的方法

  對於以上 4 個條件,只要破壞其中一個條件,就可以避免死鎖的發生。

  對於第一個條件 "互斥" 是不能破壞的,因為加鎖就是為了保證互斥。

  其他三個條件,我們可以嘗試

  一次性申請所有的資源,破壞 "佔有且等待" 條件

  佔有部分資源的執行緒進一步申請其他資源時,如果申請不到,主動釋放它佔有的資源,破壞 "不可搶佔" 條件

  按序申請資源,破壞 "迴圈等待" 條件

  使用管理類一次性申請所有的資源,破壞 "佔有且等待" 條件示例

  package constxiong.concurrency.a023;

  import java.util.HashSet;

  import java.util.Set;

  /**

  * 測試 一次性申請所有的資源,破壞 "佔有且等待" 條件示例

  * @author ConstXiong

  * @date 2019-09-24 14:04:12

  */

  public class TestBreakLockAndWait {

  //單例的資源管理類

  private final static Manger manager = new Manger();

  //資源1

  private static Object res1 = new Object();

  //資源2

  private static Object res2 = new Object();

  public static void main(String[] args) {

  new Thread(() -> {

  boolean applySuccess = false;

  while (!applySuccess) {

  //向管理類,申請res1和res2,申請失敗,重試

  applySuccess = manager.applyResources(res1, res2);

  if (applySuccess) {

  try {

  System.out.println("執行緒:" + Thread.currentThread().getName() + " 申請 res1、res2 資源成功");

  synchronized (res1) {

  System.out.println("執行緒:" + Thread.currentThread().getName() + " 獲取到 res1 資源的鎖");

  //休眠 1秒

  try {

  Thread.sleep(1000);

  } catch (Exception e) {

  e.printStackTrace();

  }

  synchronized (res2) {

  System.out.println("執行緒:" + Thread.currentThread().getName() + " 獲取到 res2 資源的鎖");

  }

  }

  } finally {

  manager.returnResources(res1, res2);//歸還資源

  }

  } else {

  System.out.println("執行緒:" + Thread.currentThread().getName() + " 申請 res1、res2 資源失敗");

  //申請失敗休眠 200 毫秒後重試

  try {

  Thread.sleep(200);

  } catch (Exception e) {

  e.printStackTrace();

  }

  }

  }

  }).start();

  new Thread(() -> {

  boolean applySuccess = false;

  while (!applySuccess) {

  //向管理類,申請res1和res2,申請失敗,重試

  applySuccess = manager.applyResources(res1, res2);

  if (applySuccess) {

  try { 無錫婦科醫院哪家好

  System.out.println("執行緒:" + Thread.currentThread().getName() + " 申請 res1、res2 資源成功");

  synchronized (res2) {

  System.out.println("執行緒:" + Thread.currentThread().getName() + " 獲取到 res1 資源的鎖");

  //休眠 1秒

  try {

  Thread.sleep(1000);

  } catch (Exception e) {

  e.printStackTrace();

  }

  synchronized (res1) {

  System.out.println("執行緒:" + Thread.currentThread().getName() + " 獲取到 res2 資源的鎖");

  }

  }

  } finally {

  manager.returnResources(res1, res2);//歸還資源

  }

  } else {

  System.out.println("執行緒:" + Thread.currentThread().getName() + " 申請 res1、res2 資源失敗");

  //申請失敗休眠 200 毫秒後重試

  try {

  Thread.sleep(200);

  } catch (Exception e) {

  e.printStackTrace();

  }

  }

  }

  }).start();

  }

  }

  /**

  * 資源申請、歸還管理類

  * @author ConstXiong

  * @date 2019-09-24 14:10:57

  */

  class Manger {

  //資源存放集合

  private Set


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69945560/viewspace-2658352/,如需轉載,請註明出處,否則將追究法律責任。

相關文章