Dining philosopher problem is one of the classic problems in computer science. I intended to implement it using Java threads. I attempted using the locking framework that came with Java 5 and used the tryLock()
method to avoid deadlock. My implementation is fairly simple. I implemented the runnable interface to represent a philosopher and used executor service to run all these runnable.
As a lock, I have used ReentrantLock
. I know there are several implementations are already discussed here, but I would like to get some review on my implementation.
import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.Random; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; public class Philosopher implements Runnable { private String name; private final Lock leftFork; private final Lock rightFork; public Philosopher(String name, Lock leftFork, Lock rightFork) { this.name = name; this.leftFork = leftFork; this.rightFork = rightFork; } public void think() { log("thinking"); } public void eat() { //assume, eating requires some time. //let's put a random number try { log("eating"); int eatingTime = getRandomEatingTime(); TimeUnit.NANOSECONDS.sleep(eatingTime); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } @Override public void run() { while (true) { keepThinkingAndEating(); } } private void keepThinkingAndEating() { think(); if (leftFork.tryLock()) { try { log("grabbed left fork"); if (rightFork.tryLock()) { try { log("grabbed right fork"); eat(); } finally { log("put down right fork"); rightFork.unlock(); } } } finally { log("put down left fork"); leftFork.unlock(); } } } private void log(String msg) { DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_TIME; String time = formatter.format(LocalDateTime.now()); String thread = Thread.currentThread().getName(); System.out.printf("%12s %s %s: %s%n", time, thread, name, msg); System.out.flush(); } private int getRandomEatingTime() { Random random = new Random(); return random.nextInt(500) + 50; } }
And the main method to run this code:
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class PhilosopherMain { public static void main(String[] args) { Lock[] forks = new Lock[5]; for (int i = 0; i < forks.length; i++) { forks[i] = new ReentrantLock(); } Philosopher[] philosophers = new Philosopher[5]; ExecutorService executorService = Executors.newFixedThreadPool(5); for (int i = 0; i < philosophers.length; i++) { Lock leftFork = forks[i]; Lock rightFork = forks[(i + 1) % forks.length]; philosophers[i] = new Philosopher("Philosopher " + (i + 1), leftFork, rightFork); executorService.execute(philosophers[i]); } executorService.shutdown(); } }