I need to do a pretty standard dining philosophers setup for my class. (I assume most people on here know what this problem is... if not look here: http://en.wikipedia.org/wiki/Dining_philosophers_problem)
We need to have a variable number of philosophers between 2 and 8, and avoid deadlock and starvation.
In my design, each philosopher thread asks a Monitor class whether it can eat.
The monitor class knows which chopsticks are to the left and right of the requesting philosopher,
so it checks whether the left chopstick is free. If not, it waits three seconds, puts it down, and tries again.
If it is free, it tries to pick up the right chopstick. If it's free, great! The philosopher eats. If it's not free, the philosopher puts down the left chopstick. Then he tries all over again.
Each philosopher is supposed to go through the cycle five times. But my code is freezing really early. There seems to be some kind of deadlock, because the last printed output is "Philosopher #i is hungry and looking for chopsticks." Like this:

Philosopher #1 is thinking deep thoughts.
Philosopher #2 is thinking deep thoughts.
Philosopher #3 is thinking deep thoughts.
Philosopher #2 is hungry and looking for chopsticks.
Philosopher #2 is eating.
Philosopher #3 is hungry and looking for chopsticks.
Philosopher #1 is hungry and looking for chopsticks.

Please help!! My code is below.

public class Philosopher implements Runnable {
	
	public final int EATS = 5;
	private int philNum;
	private int timesEaten;
	private Monitor m;
	private int state; // 0=thinking, 1=hungry, 2=eating, 3=stuffed
	
	
	Philosopher(int num, Monitor mon) {
		philNum = num;
		m=mon;
		state=0;
	}
	
	public int getPhilNum() {
		return philNum;
	}
	
	public void run () {
		try {
			// Do I need to put this in a while loop?
			for (int i=0; i<EATS; i++) {
				System.out.println("Philosopher #"+philNum+" is thinking deep thoughts.");
				Thread.sleep((long)Math.random()*3000); // The philosopher is thinking
				state=1; // The philosopher gets hungry
				// The philosopher tells the view to change his state
				System.out.println("Philosopher #"+philNum+" is hungry and looking for chopsticks.");
				m.requestEat(philNum); // The philosopher asks the monitor if he can eat
				System.out.println("Philosopher #"+philNum+" is eating.");
				state=2;
				Thread.sleep((long)Math.random()*2000); // The philosopher is eating
				m.stopEating(philNum);
				state=3;
				System.out.println("Philosopher #"+philNum+" is stuffed and putting down his chopsticks.");
				Thread.sleep((long)Math.random()*2000); // The philosopher is stuffed		
				state=0;
				timesEaten++;
				if (timesEaten==5) System.out.println("PHILOSOPHER #"+philNum+" HAS EATEN "+timesEaten+" TIMES.");
				else System.out.println("Philosopher #"+philNum+" has eaten "+timesEaten+" times.");
			}
		}
		catch (InterruptedException e) { }
		
	}
}

import java.util.concurrent.locks.*;
import java.util.concurrent.*;

public class Chopstick {

	  private boolean inUse=false;
	  private int stickNum;
	  private ReentrantLock lock = new ReentrantLock();
	  private Condition chopstickAvailableCondition = lock.newCondition();
	
	  Chopstick(int num) {
		  stickNum=num;
	  }
	  
	  synchronized boolean isInUse() {
		  return inUse;
	  }
	  
	  synchronized void putDown() {
	    inUse=false;
	    chopstickAvailableCondition.signal();
	    lock.unlock();
	  }
	
	  synchronized boolean pickUp() {
		  try {
			  lock.lock();
			  if (inUse) {
				  if (chopstickAvailableCondition.await(3, TimeUnit.SECONDS)) {
					  inUse=true;
					  return true;
				  }
				  else {
					  lock.unlock();
					  return false;
				  }
			  }
			  else {
				  inUse=true;
				  return true;
			  }
		  }
		  catch (InterruptedException e) { return false; }
	  }

}

import java.util.*;

public class Monitor {
	
	LinkedList<Philosopher> philQueue;
	private int numPhils;
	Chopstick[] chopsticks;
	
	Monitor(int numOfPhils) {
		numPhils=numOfPhils;
		chopsticks = new Chopstick[numPhils];
		for (int i=0; i<numPhils; i++) {
			chopsticks[i]=new Chopstick(i+1);
		}
		philQueue = new LinkedList<Philosopher>();
	}
	
	synchronized boolean requestEat(int pNum) {
		int currentPhil=pNum;
		int left = pNum-1; // The INDEX position of the chopstick with the same number, so subtract 1
		int right;
		if (pNum==numPhils) right = 0;
		else right = pNum; // The INDEX position of the chopstick with (the philosopher's number + 1)
		boolean success=false;
		if (chopsticks[left].pickUp()) {
			if (chopsticks[right].pickUp()) {
				success=true;
			}
			else chopsticks[left].putDown();
		}
		return success;
	}
	
	synchronized void stopEating(int pNum) {
		int left = pNum-1;
		int right;
		if (pNum==numPhils) right = 0;
		else right = pNum;
		chopsticks[left].putDown();
		chopsticks[right].putDown();
	}
	
	synchronized boolean checkChopsticks(int pNum) {
		int left = pNum-1;
		int right;
		if (pNum==numPhils) right = 0;
		else right = pNum;
		if (!chopsticks[left].isInUse() && !chopsticks[right].isInUse()) return true;
		else return false;
	}

}

public class DinnerMain {
	
	public static void main (String[] args) {
		try {
			int numPhils = Integer.parseInt(args[0]);
			Monitor m;
			if (numPhils >= 2 && numPhils <= 8) { 
				m = new Monitor(numPhils);
				Philosopher[] philosophers = new Philosopher[numPhils];
				for (int i=0; i<numPhils; i++) {
					philosophers[i]=new Philosopher(i+1, m);
				}
				for (int i=0; i<numPhils; i++) {
					new Thread(philosophers[i]).start();
				}
			}
			else {
				System.out.println("Your argument was not an integer between 2 and 8." +
				"Please try again with a valid command line argument.");
			}
			
		}
		catch (NumberFormatException e) {
			System.out.println("Your argument was not an integer between 2 and 8." +
					"Please try again with a valid command line argument.");
		}
	}

}

Lots of logic to follow.
Have you tried debugging by adding more println()s to show code flow and variable states?

Lots of logic to follow.
Have you tried debugging by adding more println()s to show code flow and variable states?

Yes, I've tried... I've never debugged with multiple threads before, and it's a bit confusing. Besides, since no exceptions are thrown, it's difficult for me to tell exactly where things are going wrong.

I don't think print statements would really help either, because there seems to be some kind of deadlock between threads going on. But I'll try.

I know it's a lot of logic to follow... It's hard to explain in any more concise terms though!

Comments in the code describing why your doing things helps others understand why you are doing things.

I don't think print statements would really help either, because there seems to be some kind of deadlock between threads going on.

Its not magic. You have to follow each thread to where it hangs and see why. Some count is wrong causing a wait that shouldn't happen for example.

This article has been dead for over six months. Start a new discussion instead.