0

I am working on a Java project to simulate the dining philosophers problem.

I started with the basic behavior, where each thread think(), getForks(), eat(), and putForks(). So there's no prevention of deadlocks or starvation (done on purpose).

The getForks() method works like this:

getForks(){
    while(forks[rightFork]==0) /*0 means fork is not on the table, so wait*/
         print(Thread #id waiting for right fork);
    forks[rightFork] = 0;
    while(forks[leftFork]==0)
         print(Thread #id waiting for left fork);
    forks[leftFork = 0;
}

I put a sleep(5000) between getting the right and the left fork, so the program is running into a deadlock (with each thread holding the right fork). What is unexpected, however, is that for some reason execution is halting once it reaches the deadlock. I expected that the "Thread #id waiting for fork" messages would keep being printed during the deadlock, but they are not. Once deadlock is reached no more messages are printed.

Any clue why?

If you want to see the whole code, here it's:

public class Philosophers{
    private static final int NUMBER = 3;
    private static final int MIN_SLEEP = 1000;
    private static final int MAX_SLEEP = 6000;
    private static Thread[] threads = new Thread[NUMBER];
    private static int[] forksArray = new int[8];

    private static void start(){
        System.out.println("Simulation started.");

        //Initialize forks array (1 means on the table)
        for(int i=0;i<7;i++)
            forksArray[i] = 1;

        //Create and start individual threads
        for(int i=0;i<NUMBER;i++){
            threads[i] = new Thread(new Philosopher(i));
            threads[i].start();
        }
    }

    public static void main(String[] args){
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                start();
            }
        });
    }

    private static class Philosopher implements Runnable{
        private int id;
        private int leftFork;
        private int rightFork;

        public void run(){
            System.out.println("Thread "+id+" started.");
            while(true){
                think();
                getForks();
                eat();
                putForks();
            }
        }

        public Philosopher(int id){
            this.id = id;
            this.rightFork = id;
            if(id==NUMBER - 1)
                this.leftFork = 0;
            else
                this.leftFork = id + 1;
        }

        public void think(){
            System.out.println("Thread "+id+" thinking...");
            try{
                int sleepInterval = MIN_SLEEP + (int)(Math.random() * ((MAX_SLEEP - MIN_SLEEP) + 1));
                Thread.sleep(sleepInterval);
            }
            catch(Exception e){
                System.out.println(e);
            }
        }

        public void getForks(){
            System.out.println("Thread "+id+" getting forks.");

            //Grab fork on the right
            while(forksArray[rightFork]==0)
                System.out.println("Thread "+id+" waiting for right fork");
            forksArray[rightFork] = 0;  

            try{
            Thread.sleep(5000);
        }   
        catch(Exception e){

        }

            //Grab fork on the left
            while(forksArray[leftFork]==0);
            System.out.println("Thread "+id+" waiting for left fork");
            forksArray[leftFork] = 0;           
        }

        public void eat(){
            System.out.println("Thread "+id+" eating.");
            try{
                Thread.sleep(2000);
            }
            catch(Exception e){
                System.out.println(e);
            }
        }

        public void putForks(){
            System.out.println("Thread "+id+" putting forks down.");
            forksArray[rightFork] = 1;
            forksArray[leftFork] = 1;
        }
    }
}
4

2 回答 2

3

我认为你的问题在这里:

while(forksArray[leftFork]==0);
System.out.println("Thread "+id+" waiting for left fork");

这 ; 在while()手段之后,它有一个空语句作为它的主体。因此,println下一行的 只会在循环终止后发生。

(顺便说一句,这就是为什么人们经常建议始终使用 {} for 循环,即使它们是单行的)

于 2013-09-23T20:21:42.090 回答
2

这并不是真正的死锁:您不使用任何锁!它只是一个无限循环。

一个问题是您没有使用正确的同步。特别是,编译器可以自由替换:

while (forksArray[leftFork] == 0);

和:

int temp = forksArray[leftFork];
while (temp == 0);

这可以在程序执行期间的任何时候发生。

简单地使您的数组易失:

private static volatile int[] forksArray = new int[8];

应该使这个问题消失。但是请注意,将数组标记为 volatile 只会阻止执行优化——这不足以使代码线程安全。

于 2013-09-23T20:19:21.750 回答