Java中的Livelock和Deadlock

时间:2020-02-23 14:37:18  来源:igfitidea点击:

下面的文章讨论java中的livelock和deadlock状态,它们是如何发生的,以及如何避免它们。

活锁

Java中的Livelock是一种递归条件,其中两个或者多个线程不断重复一段特定的代码。

当一个线程继续响应另一个线程,而另一个线程也在执行相同的操作时,就会发生Livelock。

分解起来,我们可以用以下几点来概括:

一个线程正在响应另一个线程的操作,而另一个线程也在响应前一个线程,则可能会发生livelock。

Livelock线程无法继续前进。

线程没有被阻塞;它们只是忙于相互响应。

Livelock也被称为资源匮乏的一种特殊情况

让我们通过把它与现实世界的情况联系起来来理解这个概念。考虑两辆车在一座窄桥的对面。一次只有一辆车能通过这座桥。两辆车的司机都很有礼貌,都在等对方先过桥。他们都会按喇叭来回应对方,让他们知道他们希望对方先通过。然而,两人都不过桥,一直互相按喇叭。这种情况类似于livelock。

现在让我们用一些代码来尝试这个真实的场景:

第一辆车过桥等级:

public class Car1 {
  private boolean honking = true;
  public void passBridge(Car2 car2) {
      while (car2.hasPassedBridge()) {
          System.out.println("Car1 waiting to pass the bridge");

          try {
              Thread.sleep(1000);
          } catch (InterruptedException ex) {
              ex.printStackTrace();
          }
      }

      System.out.println("Passed bridge");

      this.honking= false;
  }

  public boolean hasPassedBridge() {
      return this.honking;
  }
}

等待过桥的第二辆车的等级:

public class Car2 {
  private boolean honking = true;

  public void passBridge(Car1 car1) {

      while (car1.hasPassedBridge()) {

          System.out.println("Car 2 is waiting to pass the bridge!");

          try {
              Thread.sleep(1000);
          } catch (InterruptedException ex) {
              ex.printStackTrace();
          }
      }

      System.out.println("Car 2 has passed the bridge!");

      this.honking = false;
  }

  public boolean hasPassedBridge() {
      return this.honking;
  }
 }

主要测试等级:

public class BridgeCheck {
 static final Car2 car2 = new Car2();
 static final Car1 car1 = new Car1();
 public static void main(String[] args) {
      Thread t1 = new Thread(new Runnable() {
          public void run() {
              car2.passBridge(car1);
          }
      });
      t1.start();

      Thread t2 = new Thread(new Runnable() {
          public void run() {
              car1.passBridge(car2);
          }
      });
      t2.start();
  }
}

输出:

这将导致非终止循环。

死锁

死锁与livelock有点不同。死锁是一种状态,每个成员都在等待其他成员释放锁。

当一个线程正在等待另一个线程获取的对象锁,而第二个线程正在等待第一个线程获取的对象锁时,可能会出现这种情况。因为两个线程都在等待对方释放锁,所以这种情况称为死锁。

图:死锁状态

让我们看一个发生死锁的场景:

public class DeadlockExample{

private static String A = "Something A";
private static String B = "Something B";

  public void someFunction(){
      synchronized(A){//Jan deadlock here
          synchronized(B){
              //function does some work here
          }
      }
  }

  public void someOtherFunction(){
      synchronized(B){//Jan deadlock here
          synchronized(A){
              //the function does something here
          }   
      }
  }
}

考虑两个线程T1和T2,T1获取A并等待B来完成其功能。然而,T2获得B并等待A来完成它自己的功能。这里T1和T2正在等待被其他线程锁定的资源。因此,这是一个死锁场景。

共同避免僵局

第一个建议是避免同时使用多线程,但这在许多情况下可能并不实用。所以这个解决方案不太明智。

分析并确保在预先访问资源时没有锁。

在上面的编码示例中,为了避免死锁,只需管理资源访问的顺序(a和B访问的顺序)。

避免同时持有多个锁,以防我们必须始终以相同的顺序获取锁。

在持有锁时避免执行外来代码。

尝试使用可中断锁,这样即使遇到死锁,锁也可以被中断,并且可以毫无问题地执行进程。