前言:
本文主要讲述死锁的一个经典案例—哲学家就餐问题,并对该问题进行修复。
哲学家就餐问题是一个经典的死锁案例。在这个问题中,有五位哲学家围坐在一个圆桌周围,每位哲学家面前有一份饭菜。每位哲学家可能处于思考状态或者饥饿状态,而且每 位哲学家都有一把叉子和一把刀,用来取食饭菜。在这个问题中,每个哲学家都有可能在饥饿状态下试图取食自己面前的饭菜,但由于叉子、刀和饭菜的数量有限,可 能会出现死锁的情况。
while(true){ //思考 think(); //拿起左边的筷子 pick_up_left_fork(); //拿起右边的筷子 pick_up_right_fork(); //吃饭 eat(); //放下右边的筷子 put_down_left_fork(); //放下左边的筷子 put_down_right_fork(); }分析:如果每个哲学家同时都拿着左手的筷子,并在等右边的筷子,就会有死锁的风险。
publicclass Philosopher implements Runnable { // 堆代码 duidaima.com 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("拿起右手的筷子..."); System.out.println("吃面"); 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)); } } publicclass DiningPhilosophers { public static void main(String[] args) { //五根筷子 Object[] chopsticks = new Object[philosophers.length]; for (int i = 0; i < chopsticks.length; i++) { chopsticks[i] = new Object(); } //五个哲学家,创建5个线程,每个线程持有两把筷子锁 for (int i = 0; i < philosophers.length; i++) { Object leftChopstick = chopsticks[i]; Object rightChopstick = chopsticks[(i + 1) % chopsticks.length]; Philosopher philosophers = new Philosopher(leftChopstick, rightChopstick); new Thread(philosophers, "哲学家" + (i + 1) + "号").start(); } } }打印结果:
4.领导调节(检测与恢复策略):并不是不让你发生死锁,而是等你死锁了,领导检测到了死锁发生(五个人都拿起了左边的筷子),就会命令其中一个人放下筷子,让别人先吃。
publicclass DiningPhilosophers { public static void main(String[] args) { //五个哲学家 Philosopher[] philosophers = new Philosopher[5]; //五根筷子 Object[] chopsticks = new Object[philosophers.length]; for (int i = 0; i < chopsticks.length; i++) { chopsticks[i] = new Object(); } for (int i = 0; i < philosophers.length; i++) { Object leftChopstick = chopsticks[i]; Object rightChopstick = chopsticks[(i + 1) % chopsticks.length]; // 堆代码 duidaima.com // 修改点:这里我们将最后一个哲学家拿筷子的顺序反过来 if (i == philosophers.length - 1) { philosophers[i] = new Philosopher(rightChopstick, leftChopstick); } else { philosophers[i] = new Philosopher(leftChopstick, rightChopstick); } new Thread(philosophers[i], "哲学家" + (i + 1) + "号").start(); } } }打印结果: