哲学家就餐问题 Java语言实现

来源:互联网 发布:linux编译c文件 编辑:程序博客网 时间:2024/05/22 00:48

1. 哲学家就餐问题描述

本文部分内容来源于此,欲了解详细内容,自行点击查看。
这里写图片描述

为了不失一般性,我们假设有n个哲学家,围着餐桌思考宇宙、人生问题,每个哲学家面前有一个叉子与之对应,即:共有n个叉子;当哲学家思考一段时间后,他会拿起身边的2个叉子才能进食。进食完毕后,该哲学家放下叉子,继续思考人生、宇宙,如此往复,周而复始。

2. 解决方案

在解决该类问题时,属于竞争资源情形,假设所有哲学家均同时取得其同一方向(如左手边)的叉子时,可能出现了死锁问题。

死锁:死锁是这样一种情形,当每个进程都已经占据某个资源,同时等待另一个资源时,因为条件无法满足而使系统停滞的现象。
活锁:一个线程响应另一个线程的请求,同时另一个线程响应其他线程的请求。线程之间为响应互相的请求而实际未做任何实际工作,从而使得系统陷入饥饿状态。实例:2人A和B在走廊相向而行,A向左边移动让B通过,B向右边移动让A通过,然后反转,周而复始,实际上2人都被对方阻塞。

package com.fqyuan.philosophy;public class Philosopher implements Runnable {    // The forks on either side of this Philosopher    private Object leftFork;    private Object rightFork;    public Philosopher(Object leftFork, Object rightFork) {        this.leftFork = leftFork;        this.rightFork = rightFork;    }    private void doAction(String action) throws InterruptedException {        System.out.println(Thread.currentThread().getName() + " " + action);        Thread.sleep((int) (Math.random() * 100));    }    @Override    public void run() {        try {            while (true) {                // Thinking                doAction(System.nanoTime() + ": Thinking");                synchronized (leftFork) {                    doAction(System.nanoTime() + ": Picked up left fork.");                    synchronized (rightFork) {                        // Eating                        doAction(System.nanoTime() + ": Picked up right fork - eating.");                        // Finish eating                        doAction(System.nanoTime() + ": Put down right fork.");                    }                    // Back to thinking.                    doAction(System.nanoTime() + ": Put down left fork. Back to thinking.");                }            }        } catch (InterruptedException e) {            Thread.currentThread().interrupt();            return;        }    }}//DiningPhilosopers.javapackage com.fqyuan.philosophy;public class DinningPhilosophers {    public static void main(String[] args) {        Philosopher[] philosophers = new Philosopher[5];        Object[] forks = new Object[philosophers.length];        for (int i = 0; i < forks.length; i++)            forks[i] = new Object();        for (int i = 0; i < philosophers.length; i++) {            Object leftFork = forks[i];            Object rightFork = forks[(i + 1) % forks.length];            philosophers[i] = new Philosopher(leftFork, rightFork);            Thread t = new Thread(philosophers[i], "Philosopher " + (i + 1));            t.start();        }    }}
Philosopher 1 73695516987788: ThinkingPhilosopher 3 73695517303786: ThinkingPhilosopher 2 73695517036856: ThinkingPhilosopher 4 73695517958611: ThinkingPhilosopher 5 73695518115243: ThinkingPhilosopher 4 73695531258038: Picked up left fork.Philosopher 3 73695556574779: Picked up left fork.Philosopher 1 73695556574779: Picked up left fork.Philosopher 5 73695591774360: Picked up left fork.Philosopher 2 73695617427502: Picked up left fork.

Q:如何避免死锁发生呢?
A:打破循环等待条件,做如下修改。

package com.fqyuan.philosophy;public class DinningPhilosophers {    public static void main(String[] args) {        Philosopher[] philosophers = new Philosopher[5];        Object[] forks = new Object[philosophers.length];        for (int i = 0; i < forks.length; i++)            forks[i] = new Object();        for (int i = 0; i < philosophers.length; i++) {            Object leftFork = forks[i];            Object rightFork = forks[(i + 1) % forks.length];            // Let the last philosopher get the fork in the reversed order to            // break the circular waiting condition.            if (i == philosophers.length - 1) // Add the line here.                philosophers[i] = new Philosopher(rightFork, leftFork);            else                philosophers[i] = new Philosopher(leftFork, rightFork);            Thread t = new Thread(philosophers[i], "Philosopher " + (i + 1));            t.start();        }    }}
原创粉丝点击