javaoperating-systemsynchronizedmonitordining-philosopher

Thread.join() is not working at expect in Dining Philosophers implementation


I have implemented the Dining Philosopher problem using Monitor (Synchronized) in Java.

The goal of this program is:

I think this code seems to work fine but something is not right because it is run forever I tried to debug it and the debugging tool stop at this line philosopher[i].t.join(); but the program was not terminated.

Please help my identify the problem or show me how to fix it. Thank you for your advice.

MyMonitor class:

class MyMonitor {
    private enum States {THINKING, HUNGRY, EATING};
    private States[] state;

    public MyMonitor() {
        state = new States[5];
        for(int i = 0; i < 5; i++) {
            state[i] = States.THINKING;
            System.out.println("Philosopher " + i + " is THINKING");
        }
    }

    private void test(int i) {
        if((state[(i+4)%5]!=States.EATING) && (state[i]==States.HUNGRY) && (state[(i+1)%5]!=States.EATING)) {
            state[i] = States.EATING;
            System.out.println("Philosopher " + i + " is EATING");
            notify();
        }
    }

    public synchronized void pickup(int i) {
            state[i] = States.HUNGRY;
            System.out.println("Philosopher " + i + " is HUNGRY");      
            test(i);
            if (state[i] != States.EATING) {
                System.out.println("Philosopher " + i + " is WAITING");
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
    }

    public synchronized void putdown(int i) {
            state[i] = States.THINKING;
            System.out.println("Philosopher " + i + " is THINKING");
            test((i+4)%5);
            test((i+1)%5);
        }
    }

MyPhilosopher class:

class MyPhilosopher implements Runnable{
    private int myID;
    private int eatNum;
    private MyMonitor monitor;
    private Thread t;

    public MyPhilosopher(int myID, int eatNum, MyMonitor monitor) {
        this.myID = myID;
        this.eatNum = eatNum;
        this.monitor = monitor;
        t = new Thread(this);
        t.start();
    }

    public void run() {
        int count = 1;
        while(count <= eatNum ){
            monitor.pickup(myID);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            monitor.putdown(myID);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            count++;
        }
    }

    public static void main(String[] args) {
        int eatNum = 10;

            System.out.println("----------------------------------------------------------------------------------------------------");
        System.out.println("xxx");
        System.out.println("xxx");
        System.out.println("xxx");
            System.out.println("----------------------------------------------------------------------------------------------------");
        System.out.println("Starting");
        System.out.println("----------------------------------------------------------------------------------------------------");
        System.out.println("");
        MyMonitor monitor = new MyMonitor();
        MyPhilosopher[] philosopher = new MyPhilosopher[5];

        for(int i = 0; i < 5; i++) {
            philosopher[i] = new MyPhilosopher(i, eatNum, monitor);
        }


        for(int i = 0; i < 5; i++) {
            try {
                philosopher[i].t.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

            System.out.println("----------------------------------------------------------------------------------------------------");
        System.out.println("Ended");
    }
}

Solution

  • I have executed your code and it runs perfectly until two or more executions. In addition, you can decrease the sleep time, your code is correct but perfect until 4 pilosophers are waiting and one of them is eating. I don't like it. You are breaking out one coffman condition but i recomend you to use other implementations as by breaking hold and wait conditions. I mean, you can take both chopsticks or none, other implementation can be, even pilosophers take the chopsticks on the right and the odd pilosophers take the left one. Good Luck!

    Philosopher 4 is THINKING
    Philosopher 0 is EATING
    Philosopher 3 is HUNGRY
    Philosopher 3 is WAITING
    Philosopher 1 is HUNGRY
    Philosopher 1 is WAITING
    Philosopher 2 is THINKING
    Philosopher 3 is EATING
    Philosopher 0 is THINKING
    Philosopher 1 is EATING
    Philosopher 4 is HUNGRY
    Philosopher 4 is WAITING
    Philosopher 3 is THINKING
    Philosopher 4 is EATING
    Philosopher 2 is HUNGRY
    Philosopher 2 is WAITING
    Philosopher 0 is HUNGRY
    Philosopher 0 is WAITING
    Philosopher 1 is THINKING
    Philosopher 2 is EATING
    Philosopher 4 is THINKING
    Philosopher 0 is EATING
    Philosopher 3 is HUNGRY
    Philosopher 3 is WAITING
    Philosopher 2 is THINKING
    Philosopher 3 is EATING
    Philosopher 1 is HUNGRY
    Philosopher 1 is WAITING
    Philosopher 0 is THINKING
    Philosopher 1 is EATING
    Philosopher 4 is HUNGRY
    Philosopher 4 is WAITING
    Philosopher 3 is THINKING
    Philosopher 4 is EATING
    Philosopher 2 is HUNGRY
    Philosopher 2 is WAITING
    Philosopher 0 is HUNGRY
    Philosopher 0 is WAITING
    Philosopher 1 is THINKING
    Philosopher 2 is EATING
    Philosopher 3 is HUNGRY
    Philosopher 3 is WAITING
    Philosopher 4 is THINKING
    Philosopher 0 is EATING
    Philosopher 2 is THINKING
    Philosopher 3 is EATING
    Philosopher 1 is HUNGRY
    Philosopher 1 is WAITING
    Philosopher 4 is HUNGRY
    Philosopher 4 is WAITING
    Philosopher 0 is THINKING
    Philosopher 1 is EATING
    Philosopher 2 is HUNGRY
    Philosopher 2 is WAITING
    Philosopher 3 is THINKING
    Philosopher 4 is EATING
    Philosopher 1 is THINKING
    Philosopher 2 is EATING
    Philosopher 0 is HUNGRY
    Philosopher 0 is WAITING
    Philosopher 4 is THINKING
    Philosopher 0 is EATING
    Philosopher 3 is HUNGRY
    Philosopher 3 is WAITING
    Philosopher 2 is THINKING
    Philosopher 3 is EATING
    Philosopher 1 is HUNGRY
    Philosopher 1 is WAITING
    Philosopher 4 is HUNGRY
    Philosopher 4 is WAITING
    Philosopher 0 is THINKING
    Philosopher 1 is EATING
    Philosopher 2 is HUNGRY
    Philosopher 2 is WAITING
    Philosopher 3 is THINKING
    Philosopher 4 is EATING
    Philosopher 0 is HUNGRY
    Philosopher 0 is WAITING
    Philosopher 1 is THINKING
    Philosopher 2 is EATING
    Philosopher 4 is THINKING
    Philosopher 0 is EATING
    Philosopher 2 is THINKING
    Philosopher 1 is HUNGRY
    Philosopher 1 is WAITING
    Philosopher 0 is THINKING
    Philosopher 1 is EATING
    Philosopher 1 is THINKING
    ----------------------------------------------------------------------------------------------------
    Ended
    

    But,i have checked that you have a deadlock in some special condition like this: When all philosophers least one can eat and others are waiting. But i have changed your code in test by using synchronize in the header of the function, the if condition of the test() method by while and in the method putdown() i have changed the notify by notifyAll(); The code is this:

    class MyMonitor {
    private enum States {THINKING, HUNGRY, EATING};
    private  States[] state;
    
    public MyMonitor() {
        state = new States[5];
        for(int i = 0; i < 5; i++) {
            state[i] = States.THINKING;
            System.out.println("Philosopher " + i + " is THINKING");
        }
    }
    
    private synchronized void test(int i) {
        while((state[(i+4)%5]!=States.EATING) && (state[i]==States.HUNGRY) && (state[(i+1)%5]!=States.EATING)) {
            state[i] = States.EATING;
            System.out.println("Philosopher " + i + " is EATING");
         //   notify();
        }
    }
    
    public synchronized void pickup(int i) {
            state[i] = States.HUNGRY;
            System.out.println("Philosopher " + i + " is HUNGRY");      
            test(i);
            if (state[i] != States.EATING) {
                System.out.println("Philosopher " + i + " is WAITING");
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
    }
    
    public synchronized void putdown(int i) {
            state[i] = States.THINKING;
            System.out.println("Philosopher " + i + " is THINKING");
            //test((i+4)%5);
            //test((i+1)%5);
            notifyAll();
        }
    }
    

    I advise you to use one or more implementations and before thinking what coffman condition do you want to break. Good luck