'Is this the right way to code Dining philosopher using semaphore without any deadlock at all?

My logic to solve this puzzle is just to make left and right chopstick free, then philosopher can grab and eat. And I don't write a condition to break the while loop because I assume those philosophers eat and think 24/7/.

Is my solution deadlock free now? Feel free to give me advice. I am quite new to multithreading

import java.util.concurrent.Semaphore;
import java.util.concurrent.ThreadLocalRandom;

public class Main {

    static int philosopher = 5;
    static philosopher philosophers[] = new philosopher[philosopher];
    static chopstick chopsticks[] = new chopstick[philosopher];

    static class chopstick {

        public Semaphore mutex = new Semaphore(1);

       public synchronized void grab() {
            try {
                
                mutex.acquire();
                
               
            }
            catch (Exception e) {
                e.printStackTrace(System.out);
            }
        }

        void release() {
            mutex.release();
        }

        boolean isFree() {
            return mutex.availablePermits() > 0;
        }

    }

    static class philosopher extends Thread {

        public int number;
        public chopstick leftchopstick;
        public chopstick rightchopstick;

        philosopher(int num, chopstick left, chopstick right) {
            number = num;
            leftchopstick = left;
            rightchopstick = right;
        }

        public synchronized void run(){
 // Program wil run forever since I did not  write exit statement.
 //  Only grab when left and right chopsticks are free 
            while (true) {
                if(leftchopstick.isFree() & rightchopstick.isFree() ) {
                     leftchopstick.grab();
                     rightchopstick.grab();
                     System.out.println("philosopher " + (number+1) + " grabs left chopstick.");
                     System.out.println("philosopher " + (number+1) + " grabs right chopstick.");
                     
                     eat();
                     leftchopstick.release();
                     System.out.println("philosopher " + (number+1) + " releases left chopstick.");
                     rightchopstick.release();
                     System.out.println("philosopher " + (number+1) + " releases right chopstick.");
                }
                
            
               
            }
        }

        void eat() {
            try {
                int sleepTime = ( 1000);
                System.out.println("philosopher " + (number+1) + " eats for " + sleepTime  + "miliseconds");
                Thread.sleep(sleepTime);
            }
            catch (Exception e) {
                e.printStackTrace(System.out);
            }
        }

    }

    public static void main(String argv[])  {

        for (int i = 0; i < philosopher; i++) {
            chopsticks[i] = new chopstick();
        }

        for (int i = 0; i < 5; i++) {
            philosophers[i] = new philosopher(i, chopsticks[i], chopsticks[(i + 1) % philosopher]);
            philosophers[i].start();
        }

        while (true) {
            try {
                // sleep 1 sec
                Thread.sleep(1000);

                // check for deadlock
                boolean deadlock = true;
                for (chopstick f : chopsticks) {
                    if (f.isFree()) {
                        deadlock = false;
                        break;
                    }
                }
                
                if (deadlock) {
                    
                    System.out.println("Dead lock occurs cause Everyone grab left chopstick at the same time");
                    break;
                }
            }
            catch (Exception e) {
                e.printStackTrace(System.out);
            }
        }

        System.out.println("Exit The Program!");
        System.exit(0);
    }

}


Solution 1:[1]

Here is one way that your program, in theory, could deadlock:

  1. All the chopsticks are free,
  2. All of the philosophers simultaneously look at the chopsticks, and see that they are free (leftchopstick.isFree() && rightchopstick.isFree()),
  3. All of the philosophers simultaneously grab their left chopstick,
  4. Each of them now is stuck, waiting for his neighbor to the right to put down his their right (the neighbor's left) chopstick.

Problem 2: The condition that no chopstick is free is insufficient to prove a deadlock. Two philosophers could be eating at the same time (i.e., four chopsticks in-use) while a third philosopher is holding the fifth chopstick in his left hand, waiting for the right-hand neighbor to put chopsticks down. None of the five chopsticks is free in that case, but the two philosophers who are eating eventually will finish, and put their chopsticks down, and the program will continue to run...

...Or, at least, it would have done if your main thread had not declared a deadlock, and aborted the program.


Both of the problems that I've highlighted here have the same root: You appear to believe that the testing and acquiring of chopsticks happens _atomically.

if(leftchopstick.isFree() & rightchopstick.isFree() ) {
    leftchopstick.grab();
    rightchopstick.grab();
    ...
}

That is to say, You seem to think that no other philosopher can act while one philosopher is looking at chopsticks and picking them up. But that isn't true: After philosopher P has seen that their left chopstick is free, the neighbor to the left could pick it up while P is looking to the right. After P has decided that both are free, the left neighbor still could win the race to pick up the left chopstick, and even if leftchopstick.grab() succeeds, the neigbor to the right still could win the race to grab the other one.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1