哲学家就餐问题

时间:2021-09-26 00:11:21

假设有五位哲学家围坐在一张圆形餐桌旁,做以下两件事情之一:吃饭,或者思考。吃东西的时候,他们就停止思考,思考的时候也停止吃东西。餐桌中间有一大碗意大利面,每两个哲学家之间有一只餐叉。因为用一只餐叉很难吃到意大利面,所以假设哲学家必须用两只餐叉吃东西。他们只能使用自己左右手边的那两只餐叉。哲学家就餐问题有时也用米饭和筷子而不是意大利面和餐叉来描述,因为很明显,吃米饭必须用两根筷子。哲学家从来不交谈,这就很危险,可能产生死锁,每个哲学家都拿着左手的餐叉,永远都在等右边的餐叉(或者相反)。即使没有死锁,也有可能发生资源耗尽。

/**
 * 筷子
 */
public class Chopstick {
    private boolean taken=false;
    public synchronized void take() throws InterruptedException{
        while (taken){
            wait();
        }
        taken=true;
    }
    public synchronized void drop(){
        taken=false;
        notifyAll();
    }
}
/**
 * 哲学家
 */
public class Philosopher implements Runnable{
    private Chopstick left;
    private Chopstick right;
    private final int id;
    private final int ponderFactor;
    private Random rand=new Random(47);
    private void pause() throws InterruptedException{
        if(ponderFactor==0) return;
        TimeUnit.MILLISECONDS.sleep(rand.nextInt(ponderFactor*250));
    }
    public Philosopher(Chopstick left,Chopstick right,int ident ,int ponder){
        this.left=left;
        this.right=right;
        id=ident;
        ponderFactor=ponder;
    }

    @Override
    public void run() {
        try {
            while(!Thread.interrupted()){
                System.out.println(this+" "+" thinking");
                pause();
                System.out.println(this+" "+"grabbing right");
                right.take();
                System.out.println(this+" "+" grabbing left");
                left.take();
                System.out.println(this+" eating");
                pause();
                right.drop();
                left.drop();
            }
        } catch (InterruptedException e) {
            System.out.println(this+" exiting via interrupt");
        }
    }
    public String toString(){
        return "Philosopher "+id;
    }
}
public class DeadlockingDiningPhilosophers {
    public static  void main(String[] args)throws  Exception{
        int ponder=0;
        int size=5;
        ExecutorService exec= Executors.newCachedThreadPool();
        Chopstick[] sticks=new Chopstick[size];
        for(int i=0;i<size;i++)
            sticks[i]=new Chopstick();
        for(int i=0;i<size;i++)
            exec.execute(new Philosopher(sticks[i],sticks[(i+1)%size],i,ponder));
        System.out.println("Press 'Enter' to quit");
        System.in.read();
        exec.shutdownNow();
    }
}