13-死锁代码

nobility 发布于 2021-05-22 2210 次阅读


死锁代码

最简单死锁情况

public static void main(String[] args) throws InterruptedException {
  Object lock1 = new Object();
  Object lock2 = new Object();
  new Thread(() -> {
    synchronized (lock1) {
      System.out.println(Thread.currentThread().getName() + "获得了lock1");
      try {
        Thread.sleep(1000);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      synchronized (lock2) {
        System.out.println(Thread.currentThread().getName() + "获得了lock2");
      }
    }
  }).start();
  new Thread(() -> {
    synchronized (lock2) {
      System.out.println(Thread.currentThread().getName() + "获得了lock1");
      try {
        Thread.sleep(1000);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      synchronized (lock1) {
        System.out.println(Thread.currentThread().getName() + "获得了lock2");
      }
    }
  }).start();
}

银行转账问题

import java.util.Random;

public class Main {

  public static void main(String[] args) throws InterruptedException {
    //mustDeadLock(); //必然死锁
    randomDeadLock(100, 20);  //随机死锁
  }

  public static Account[] initAccount(int count) {  //批量账户初始化,每个账户余额在1000到2000之间
    Account[] accounts = new Account[count];
    Random random = new Random(); //用于生成随机数
    for (int i = 0; i < accounts.length; i++) {
      accounts[i] = new Account("account" + i, 1000 + random.nextInt(1000));
    }
    return accounts;
  }

  public static void randomTransferMoney(Account[] accounts) {  //随机转账
    Random random = new Random(); //用于生成随机数
    for (int i = 0; i < accounts.length; i++) {
      int fromAccountIndex = random.nextInt(accounts.length);
      int toAccountIndex = random.nextInt(accounts.length);
      int amount = 100 + random.nextInt(500);  //转账钱数是100到500之间
      int time = random.nextInt(1000);  //转账延时时间
      new TransferMoney(accounts[fromAccountIndex], accounts[toAccountIndex], time).transferMoney(amount);
    }
  }

  public static void mustDeadLock() {  //必然死锁的情况
    Account accountA = new Account("A", 500);
    Account accountB = new Account("B", 500);
    new Thread(() ->
        new TransferMoney(accountA, accountB, 100).transferMoney(200)
    ).start();
    new Thread(() ->
        new TransferMoney(accountB, accountA, 100).transferMoney(200)
    ).start();
  }

  public static void randomDeadLock(int accountCount, int threadCount) {  //随机死锁的情况
    Account[] accounts = initAccount(accountCount);  //批量初始化账户开启不同线程进行转账,账户量容易出现死锁
    for (int i = 0; i < threadCount; i++) {
      new Thread(() -> {
        randomTransferMoney(accounts);
      }).start();
    }
  }
}

class Account {  //账户类
  private String name;  //账户名
  private int balance;  //账户余额

  public Account(String name, int balance) {
    this.name = name;
    this.balance = balance;
  }

  public void setBalance(int balance) {
    this.balance = balance;
  }

  public int getBalance() {
    return balance;
  }

  public String getName() {
    return name;
  }

  @Override
  public String toString() {
    return "账户" + name + "的余额为" + balance;
  }
}

class TransferMoney {
  private Account from;  //转出账户
  private Account to;  //转入账户
  private int time;  //转账延时时间,单位毫秒,默认0

  public TransferMoney(Account from, Account to, int time) {
    this.from = from;
    this.to = to;
    this.time = time;
  }

  public TransferMoney(Account from, Account to) {
    this(from, to, 0);
  }

  public void transferMoney(int amount) {
    synchronized (from) {
      int balance = from.getBalance();  //查看余额是否充足
      if (balance - amount < 0) {
        System.out.println("余额不足,转账失败");
        return;
      }
      if (time > 0) {  //设置时间就延时,若设置转账延时就会进入死锁状态
        try {
          Thread.sleep(time);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
      synchronized (to) {
        from.setBalance(balance - amount);  //转账操作
        to.setBalance(to.getBalance() + amount);
        System.out.println("从" + from.getName() + "到" + to.getName() + ",成功转账" + amount + "元");
      }
    }
  }
}

哲学家就餐问题

问题描述:有五位哲学家围坐在一张圆形餐桌旁,哲学家只能做吃饭或思考这两件事,餐桌中间有饭,每位哲学家之间各有一只筷子,哲学家必须用两只筷子吃东西,并且只能使用自己左右手边的那两只筷子

在不考虑意大利面有多少,也不考虑哲学家的胃有多大,设计一套规则,使得在哲学家们在完全不交谈,也就是无法知道其他人可能在什么时候要吃饭或者思考的情况下,可以在这吃饭思考两种状态下永远交替下去

产生死锁的情况:每个哲学家都拿起左手的筷子,永远等待右边的筷子,反之依然

class Philosopher implements Runnable {  //哲学家类
  private Object leftChopstick;
  private Object rightChopstick;

  public Philosopher(Object leftChopstick, Object rightChopstick) {
    this.leftChopstick = leftChopstick;
    this.rightChopstick = rightChopstick;
  }

  @Override
  public void run() {  //哲学家的动作,吃饭或思考
    try {
      while (true) {
        doAction("思考中");
        synchronized (leftChopstick) {
          doAction("拿起左边的筷子");
          synchronized (rightChopstick) {
            doAction("拿起右边的筷子 -> 开始进食");
            doAction("放下右边的筷子");
          }
          doAction("放行左边的筷子");
        }
      }
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }

  private void doAction(String action) throws InterruptedException {  //哲学家所作的动作
    System.out.println(Thread.currentThread().getName() + " -> " + action);
    Thread.sleep((long) (Math.random() * 10));  //该动作持续随机时间
  }
}

public class DiningPhilosophers {

  public static Object[] initChopsticks(int count) {
    Object[] chopsticks = new Object[count];
    for (int i = 0; i < chopsticks.length; i++) {  //初始化筷子
      chopsticks[i] = new Object();
    }
    return chopsticks;
  }

  public static Philosopher[] initPhilosophers(Object[] chopsticks) {
    Philosopher[] philosophers = new Philosopher[chopsticks.length];
    for (int i = 0; i < philosophers.length; i++) {  //初始化哲学家
      Object leftChopstick = chopsticks[i];
      Object rightChopstick = chopsticks[(i + 1) % chopsticks.length];  //使用取余方式取到哲学家两测的筷子
      philosophers[i] = new Philosopher(leftChopstick, rightChopstick);
    }
    return philosophers;
  }

  public static void main(String[] args) {
    Object[] chopsticks = initChopsticks(5);
    Philosopher[] philosophers = initPhilosophers(chopsticks);
    for (int i = 0; i < philosophers.length; i++) {
      new Thread(philosophers[i], "哲学家" + (i)).start();  //启动哲学家线程
    }
  }
}

死锁的必要条件

以下四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要一个条件不满足,就不会发生死锁

  1. 互斥条件:一个资源只能同时被一个进程或线程使用
  2. 请求与保持条件:一个进程或线程,因请求资源而阻塞时,对已获得的资源保持不放
  3. 不剥夺条件:进程或线程,已获得的资源,在末使用完之前,不能被外界强行剥夺
  4. 循环等待条件:若干进程或线程之间,形成一种头尾相接的循环等待资源关系
此作者没有提供个人介绍
最后更新于 2021-05-22