threaded app hanging

Tagged:  

Hi,

This is completely off topic but I figured I'd chance it in the hope someone here can help me. I'm having a problem with Java. It's a multi-threaded program where one "Agent" thread makes resources available to 3 other threads (Smokers). The smokers then use the resources, and notify the agent when they are finished so the agent can put another round on the table. The actual question is below.

I need to have this thing ready for tonight and I've tried everything I can think of. It just seems to hang every time. I think it's either not notifying properly or it's getting deadlock, but I can't see where as I have guards in place to prevent deadlock. What I'm saying pretty much is that if anyone can help, even to just point me in the right direction, or ballpark area, I would really appreciate it.

Here's the question:

Three smokers around a table. Only one can smoke at a time. To smoke a smoker needs 3 ingredients: tobacco, paper, and a match. Each smoker has an infinite supply of just one of these ingredients and must wait for the other two to be made available by a smokers agent. The smokers agent has an infinite supply of all three ingredients. The agent places two ingredients on the table and waits for a smoker to make a cigarette and smoke it. When the smoker is finished smoking it notifys the agent that another round of ingredients should be places on the table to allow smoking to continue. In the way smokers can continue smoking in some order forever!

The code's below, I've put in comments where appropriate (I hope it makes sense):
________________________________________________________


class Main {
 public static void main(String args[]) {

  Resources resources = new Resources();

  Agent agent = new Agent(resources);
  Smoker smoker1 = new Smoker(0,resources);
  Smoker smoker2 = new Smoker(1,resources);
  Smoker smoker3 = new Smoker(2,resources);
   
  agent.start();
  smoker1.start();
  smoker2.start();
  smoker3.start(); 

  // wait on threads to finish
  try {
   agent.join();
   smoker1.join();
   smoker2.join();
   smoker3.join();
  } catch(InterruptedException e){}

 }
// end of Main class
}

// Resources class
class Resources {

 volatile boolean tobacco;
 volatile boolean paper;
 volatile boolean match;

 // default constructor
 public Resources() {
  this.tobacco = false;
  this.paper = false;
  this.match = false;
 }

 synchronized void getResources(int threadno){
  // if thread has tobacco
  if (threadno==0) {
     // while paper and match are false
     while(!paper || !match){
      try{ wait(); } catch(InterruptedException e){}
     }
     paper = false;
     match = false;
     System.out.println("Thread "+threadno+" took paper and match...");
   }
   // if thread has paper
   else if (threadno==1) {
     // while tobacco and match are false
     while(!tobacco || !match){
      try{ wait(); } catch(InterruptedException e){}
     }
     match = false;
     tobacco = false;
     System.out.println("Thread "+threadno+" took match and tobacco...");
   }
   // if thread has match
   else {
     // while tobacco and paper are false
     while(!tobacco || !paper){
      try{ wait(); } catch(InterruptedException w){}
     }
     tobacco = false;
     paper = false;
     System.out.println("Thread "+threadno+" took tobacco and paper...");
   }
   notify();
 }

 synchronized void makeAvailable(int material){
  while(tobacco || paper || match){
   try{ wait();} catch(InterruptedException e){}
  }
  // if we're not putting down tobacco then
  if (material==0) {
   paper = true;
   match = true;
  }
  // else if we're not putting down paper
  else if (material==1) {
   tobacco = true;
   match = true;
  }
  // else if we're not puting down match
  else {
   tobacco = true;
   paper = true;
  }
  notify();
  System.out.println("Agent put new materials on table for "+material+"...");
 }

// end of Resources class
}

// Agent class
class Agent extends Thread {
 
 private Resources resources;

 // default constructor
 public Agent(Resources resources) {
  this.resources = resources;
 }

 // Agent run() method
 public void run() {
  for(;;) {
   resources.makeAvailable((int)(Math.random()*3));
  }
 }

// end of Agent class
}

// Smoker class
class Smoker extends Thread {

 private int threadno;
 private Resources resources;
 
 // default constructor
 public Smoker(int threadno,Resources resources) {
  this.threadno = threadno;
  this.resources = resources;
 }

 public void run(){
  for(;;) {
   resources.getResources(threadno); 
  }
 }

// end of Smoker class
}