Java多线程中的Livelock

时间:2020-01-09 10:35:08  来源:igfitidea点击:

在多线程环境中,一个线程通常会响应另一个线程的操作而起作用。如果另一个线程的操作也是对另一个线程的操作的响应,则如果两个或者多个线程正在忙于响应彼此的操作并且无法在此过程中取得进一步的进展,则可能会发生活锁。

如果我们以三个线程为例,其中

  • 线程1正在响应线程2的响应
  • 线程2正在响应来自线程3的响应
  • 线程3作用于来自线程1的响应

因此,这三个线程忙于响应彼此的操作,因此由于存在活锁而无法取得任何进展。

活锁与死锁有何不同

在发生动态锁的情况下,就像死锁一样,线程不会取得任何进展,但不会像死锁那样被阻塞。线程处于活动状态,但是它们忙于彼此响应,因此没有任何进展。

Java Livelock示例

在该示例中,客户和商店有两个线程,客户在付款之前正在等待订单发货,而商店只在获得金额后才愿意发货。因此,除非满足事件条件,否则两个线程都对事件做出响应,但是它们本身却很忙。

public class ThreadLiveLock {
  static final Customer customer = new Customer();
  static final Shop shop = new Shop();
  public static void main(String[] args) {
    Thread thread1 = new Thread(new Runnable() {
      @Override
      public void run() {
        customer.payMoney(shop);	
      }
    });
    
    Thread thread2 = new Thread(new Runnable() {
      @Override
      public void run() {
        shop.shipOrder(customer);	
      }
    });

    thread1.start();
    thread2.start();
  }
}

class Customer{
  private boolean paid = false;
  public void payMoney(Shop shop){
    while(!shop.isOrderShipped()){
      System.out.println("waiting for order");
      try {
        Thread.sleep(1000);
      } catch (InterruptedException ex) {
        ex.printStackTrace();
      }
    }
    setPaid(true);
  }
  public boolean isPaid() {
    return paid;
  }
  public void setPaid(boolean paid) {
    this.paid = paid;
  }
}

class Shop{
  private boolean orderShipped = false;
  public void shipOrder(Customer customer){
    while(!customer.isPaid()){
      System.out.println("waiting for money");
      try {
        Thread.sleep(1000);
      } catch (InterruptedException ex) {
        ex.printStackTrace();
      }			
    }
    setOrderShipped(true);
  }

  public void setOrderShipped(boolean orderShipped) {
    this.orderShipped = orderShipped;
  }

  public boolean isOrderShipped() {
    return orderShipped;
  }
}

输出:

waiting for order
waiting for money
waiting for money
waiting for order
waiting for order
waiting for money
waiting for money
waiting for order