// : c13:DiningPhilosophers.Java
// Demonstrates how deadlock can be hidden in a program.
// {Args: 5 0 deadlock 4}
// From 'Thinking in Java, 3rd ed.' (c) BrUCe Eckel 2002
// www.BruceEckel.com. See copyright notice in CopyRight.txt.
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
class Chopstick {
private static int counter = 0;
private int number = counter++;
public String toString() {
return "Chopstick " + number;
}
}
class Philosopher extends Thread {
private static Random rand = new Random();
private static int counter = 0;
private int number = counter++;
private Chopstick leftChopstick;
private Chopstick rightChopstick;
static int ponder = 0; // Package Access
public Philosopher(Chopstick left, Chopstick right) {
leftChopstick = left;
rightChopstick = right;
start();
}
public void think() {
System.out.println(this + " thinking");
if (ponder > 0)
try {
sleep(rand.nextInt(ponder));
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
public void eat() {
synchronized (leftChopstick) {
System.out.println(this + " has " + this.leftChopstick
+ " Waiting for " + this.rightChopstick);
synchronized (rightChopstick) {
System.out.println(this + " eating");
}
}
}
public String toString() {
return "Philosopher " + number;
}
public void run() {
while (true) {
think();
eat();
}
}
}
public class DiningPhilosophers {
public static void main(String[] args) {
if (args.length < 3) {
System.err.println("usage:\n"
+ "java DiningPhilosophers numberOfPhilosophers "
+ "ponderFactor deadlock timeout\n"
+ "A nonzero ponderFactor will generate a random "
+ "sleep time during think().\n"
+ "If deadlock is not the string "
+ "'deadlock', the program will not deadlock.\n"
+ "A nonzero timeout will stop the program after "
+ "that number of seconds.");
System.exit(1);
}
Philosopher[] philosopher = new Philosopher[Integer.parseInt(args[0])];
Philosopher.ponder = Integer.parseInt(args[1]);
Chopstick left = new Chopstick(), right = new Chopstick(), first = left;
int i = 0;
while (i < philosopher.length - 1) {
philosopher[i++] = new Philosopher(left, right);
left = right;
right = new Chopstick();
}
if (args[2].equals("deadlock"))
philosopher[i] = new Philosopher(left, first);
else
// Swapping values prevents deadlock:
philosopher[i] = new Philosopher(first, left);
// Optionally break out of program:
if (args.length >= 4) {
int delay = Integer.parseInt(args[3]);
if (delay != 0)
new Timeout(delay * 1000, "Timed out");
}
}
} ///:~
class Timeout extends Timer {
public Timeout(int delay, final String msg) {
super(true); // Daemon thread
schedule(new TimerTask() {
public void run() {
System.out.println(msg);
System.exit(0);
}
}, delay);
}
} ///:~