0

我写了这个餐饮哲学家的代码,但最后一个线程没有产生所需的“xxx已经完成他的晚餐”行?我做错什么了?

似乎最后一个线程过早终止。

我将不胜感激这方面的任何帮助。

import java.util.Random;



public class DiningPhilosophers {



    //An array holding all the chopsticks
    private final Chopstick[] chopsticks = new Chopstick[5];

    /*Constructor for the main class
    * Creates all the chopsticks 
    * Creates and starts all the threads*/
    public DiningPhilosophers(){
        putChopsticksOnTheTable();
        Thread t1 = new Thread(new Philosopher("First",this.chopsticks[4],this.chopsticks[0]));
        Thread t2 = new Thread(new Philosopher("Second",this.chopsticks[0],this.chopsticks[1]));
        Thread t3 = new Thread(new Philosopher("Third",this.chopsticks[1],this.chopsticks[2]));
        Thread t4 = new Thread(new Philosopher("Fourth",this.chopsticks[2],this.chopsticks[3]));
        Thread t5 = new Thread(new Philosopher("Fifth",this.chopsticks[3],this.chopsticks[4]));
        t1.start();
        t2.start();
        t3.start();
        t4.start();
        t5.start();


    }

    /*Initialise the chopsticks in the array*/
    private void putChopsticksOnTheTable(){
        for(int i = 0;i < chopsticks.length;i++)
        chopsticks[i]= new Chopstick(); 
    }

    public static void main(String[] args){
        new DiningPhilosophers();
    }
}


class Philosopher extends Thread{
private static final int EATING_TIME_LIMIT = 1000;
private static final int THINKING_TIME_LIMIT = 800;
private int EAT_TIMES = 5;
private final Random randomise = new Random();
private final Chopstick _leftChopstick;
private final Chopstick _rightChopstick;
private final String _name;
private State _state;

/* Enumeration class that holds 
* information about the possible 
* Philosopher's states 
*/
public enum State {
    EATING, THINKING
}

/*
* Main constructor for the Philosopher class
* @param name   the name of the Philosopher
* @param leftChopstick  the chopstick that is currently on the left of the Philosopher
* @param rightChopstick the chopstick currently on the right of the Philosopher
* 
*/
public Philosopher(String name, Chopstick leftChopstick, Chopstick rightChopstick) {

    this._leftChopstick = leftChopstick;
    this._rightChopstick = rightChopstick;
    this._name = name;

}

/*
* The method eat that uses two chopsticks. It blockes the two Chopstick
* objects so they could not be changed then it changes their state 
* as well as the state of the philosopher
* At the end of the method, the chopsticks' state is reverted and
* the Philosopher goes into the Thinking state 
*/
private void tryToEat() throws InterruptedException 
{       

     synchronized(_leftChopstick){
            while(_leftChopstick.inUse() || _rightChopstick.inUse())

                try{
                    //this.setPhilosopherState(Philosopher.State.WAITING);
                    _leftChopstick.wait();
                }catch (InterruptedException e){}
                    synchronized(_rightChopstick) {
                    try{
                        Thread.sleep(1);
                        _leftChopstick.pickUp();
                        System.out.println(_name + " picks up the left chopstick...");
                        _rightChopstick.pickUp();
                        System.out.println(_name + " picks up the right chopstick...");
                        eat();
                    }
                    finally {
                        _leftChopstick.putDown();
                        System.out.println(_name + " puts down the left chopstick...");
                        _rightChopstick.putDown(); 
                        System.out.println(_name + " puts down the right chopstick...");
                        //_leftChopstick.notify();
                        //_rightChopstick.notify();   
                    }
                    }
               }


    if(this.EAT_TIMES > 0)
            think();  

}

private void eat() throws InterruptedException
{
    setPhilosopherState(State.EATING);
    Thread.sleep(randomise.nextInt(EATING_TIME_LIMIT));        
    this.EAT_TIMES--;
    if(this.EAT_TIMES == 0)
        System.out.println("***************************" + _name + " has finished his dinner");
}

/*
* This method only changes the state 
* of the Philosopher to Thinking
*/
private void think() throws InterruptedException{
    setPhilosopherState(Philosopher.State.THINKING);
    Thread.sleep(randomise.nextInt(THINKING_TIME_LIMIT));
}

/*
* Set the current state of the Philosopher
*/
private void setPhilosopherState(State state){
    this._state = state;        

    if(_state == State.EATING)
        System.out.println ("*** " + _name + " is EATING for the " + (6 - EAT_TIMES) + " time!");
    else
        System.out.println( _name + " is THINKING...");
}

/*
* Get the current state of the Philosopher
*/
public State getPhilosopherState(){
    return _state;
}

/*
* The method is invoked with the start of the thread
* and runs the eat function for 10 times
*/
public void run(){
    while(this.EAT_TIMES > 0){
        try {
            tryToEat();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


}    

}


class Chopstick
{
   private boolean _inUse;

    /*
    * @return the current state of the chopstick
    */
    public boolean inUse(){
        return _inUse; 
    }

    /*
    * @param usedFlag the new state of the chopstick
    */
    public synchronized void pickUp()
    {           
        _inUse = true;
    }

    public void putDown()
    {
        _inUse = false;
        this.notify();
    }
}
4

3 回答 3

2

这是关于为什么应该同步对所有共享可变数据的访问的很好的一课。您Chopstick的字段不是易失性的,但可以由多个线程通过inUse. 唯一没有同步被引用的地方inUse

while (_leftChopstick.inUse() || _rightChopstick.inUse())

如果没有同步rightChopstick.inUse(),可能会通过数据竞争返回意外的值。结果,所有挂起的线程都卡在

_leftChopstick.wait();

如果你同步inUse,你应该让它正确完成。另外我强烈建议同步所有方法Chopstick

于 2013-04-08T16:35:33.890 回答
1

在 Chopstick 类中还需要同步pickUp()方法,否则该值可能对其他线程不可见:

    public synchronized void pickUp() {
        _inUse = true;
    }

或者干脆使用 AtomicBoolean。

于 2013-04-08T09:07:00.003 回答
0

没有必要打电话

Thread t1 = new Thread(new Philosopher(...));

您可以改为致电

Thread t1 = new Philosopher(...);

为了确保所有线程完成它们的工作,调用它们的 .join 方法。这将在退出 DiningPhilosophers 构造函数之前等待线程终止。

t1.start();
....
t5.start();
t1.join();
...
t5.join();
于 2013-04-08T16:00:46.233 回答