Concurrent Programming with Java
Lab Manual, Version 1.0, F. Astha Ekadiyanto, 2002.

[Contents] [Next] [Previous]

Lab 6: Monitors and Thread Synchronization 2


Dining Philosophers scenario: DiningPhilosophers Class (The Applet)

Conceptually, the Applet will have the following user interface design:

All the philosophers will be drawn in an AnimationCanvas (an inner Class defined here) that represents the current states of philosophers and the forks. Here we see that the Applet can also detect a deadlock condition where all the philosophers circulary holds one fork in one hand and trying to get another but have to wait forever.

This condition is the ultimate symptom of deadlock (which is the deadlock itself) which is the Wait-for cycle.

In addition to the animation, the Applet provides a small interface using a Scrollbar to enable users to control the Animation speed namely the time range used in the Thinking and Eating process.

 

To shorthen the discussion, the Applet code is presented below completely to enable a simple cut and paste process.

Class name: DiningPhilosophers

import java.applet.*;
import java.awt.*;
import java.awt.event.AdjustmentListener;
import java.awt.event.AdjustmentEvent;
import java.awt.image.BufferedImage;
import java.lang.Math;
/**
* The class DiningPhilosophers demonstrates the problem of the dining
* philosophers. 
* Modified from Stephan Fischli Philosopher's Code
* @version 1.1
*/


public class DiningPhilosophers extends Applet implements AdjustmentListener
{
   /**
   * The Dining Philosopher's graphical representation.
   */
   private AnimationCanvas theAnimation;

   /**
   * The Label to indicate Philosopher's thread timing.
   */
   private Label speedvalue;

   /**
   * The size of the round table.
   */
   private int radius = 120;
   /**
   * The initial number of philosophers.
   */
   public int nphils = 5;
   /**
   * The forks.
   */
   private Fork[] forks;
   /**
   * The philosophers.
   */
   private Philosopher[] philosophers;
   /**
   * The images of a philosopher.
   */
   private Image[] philImages;
   /**
   * The images of a fork.
   */
   private Image[] forkImages;
   /**
   * The images of a table.
   */
   private Image[] tableImages;
   /**
   * Initializes the applet.
   */
   public void init()
   {
       // get parameters and count radius property
       try {
           nphils = Integer.parseInt( getParameter( "nphils" ) );
       }
       catch ( Exception e ) {}
       radius = (int)(radius > ((105*nphils)/(2*Math.PI))
                ? radius:((105*nphils)/(2*Math.PI)));
       // load images
       forkImages = loadImages( "fork", 2 );
       philImages = loadImages( "phil", 6 );
       tableImages = loadImages( "table", 1 );

       // Putting Animation Canvas
       setLayout ( new BorderLayout()); 
       theAnimation = new AnimationCanvas();
       theAnimation.setSize(2*(radius+70),2*(radius+70));
       add(theAnimation, BorderLayout.NORTH);

       // Defining User Interface
       Panel controlPanel= new Panel();
       controlPanel.setLayout( new BorderLayout());
       controlPanel.add(new Label("Adjust Animation Speed :"),BorderLayout.WEST);

       Scrollbar timeadjust = new Scrollbar(Scrollbar.HORIZONTAL, 
                                              Philosopher.speed, 0, 0, 10000);
       timeadjust.setBlockIncrement(100);
       timeadjust.setUnitIncrement(100); 
       timeadjust.addAdjustmentListener(this);
       controlPanel.add(timeadjust,BorderLayout.CENTER);

       speedvalue = new Label(Philosopher.speed+"");
       controlPanel.add(speedvalue,BorderLayout.EAST);
       add(controlPanel,BorderLayout.SOUTH);

       // Resize Applet
       setSize(2*(radius+70),2*(radius+70)+30);
       setBackground( Color.white );
   }
   /**
   * Creates and starts the philosophers.
   */
   public void start()
   {
       // create forks
       forks = new Fork[nphils];
       for ( int i = 0; i < nphils; i++ )
       forks[i] = new Fork();
       // create philosophers
       philosophers = new Philosopher[nphils];
       for ( int i = 0; i < nphils; i++ ) 
       {
           Fork leftFork = forks[i];
           Fork rightFork = forks[(i+1)%nphils];
           philosophers[i] = new Philosopher( i, leftFork, rightFork );
       }
       // start philosophers
       for ( int i = 0; i < nphils; i++ ) 
       {
           philosophers[i].start();
       }
   }
  /**
   * Loads an array of images.
   * @param name the name of the images
   * @param num the number of images
   */
   private Image[] loadImages( String name, int num )
   {
       Image[] images = new Image[num];
       for ( int i = 0; i < num; i++ ) 
       {
           String filename = "img/" + name + i + ".gif";
           images[i] = getImage( getDocumentBase(), filename );
       }
       return images;
   }
   /**
   * Action Listener for Scrollbar AdjustmentEvent
   * @param AdjustmentEvent The Event object
   */
   public void adjustmentValueChanged(AdjustmentEvent e)
   {
       int speed = e.getValue();
       speedvalue.setText(speed+"");
       Philosopher.speed = speed;
   }
   /**
   * The Class AnimationCanvas to represent the Graphics of DiningPhilosopher states
   * Contains only paint method and refer directly to Applet fields.
   */
   class AnimationCanvas extends Canvas
   {
       public void paint( Graphics g )
       {
           // draw philosophers
           boolean deadlock = true;
           for ( int i = 0; i < nphils; i++ ) 
           {
               Image image = null;
               int x = (int) (radius + 70 + (radius+35) 
* Math.cos(2*Math.PI*(i+0.5)/nphils))-35; int y = (int) (radius + 70 + (radius+35) * Math.sin(2*Math.PI*(i+0.5)/nphils))-35; switch ( philosophers[i].state() ) { case Philosopher.THINKING: image = philImages[0]; deadlock = false; break; case Philosopher.TAKING_FIRST_FORK_LEFT: //Adjust left-right orientation due to circular position if (i+0.5 > (nphils/2)) image = philImages[1]; else image = philImages[2]; deadlock = false; break; case Philosopher.TAKING_FIRST_FORK_RIGHT: //Adjust left-right orientation due to circular position if (i+0.5 > (nphils/2)) image = philImages[2]; else image = philImages[1]; deadlock = false; break; case Philosopher.TAKING_SECOND_FORK_RIGHT: //Adjust left-right orientation due to circular position if (i+0.5 > (nphils/2)) image = philImages[3]; else image = philImages[4]; break; case Philosopher.TAKING_SECOND_FORK_LEFT: //Adjust left-right orientation due to circular position if (i+0.5 > (nphils/2)) image = philImages[4]; else image = philImages[3]; break; case Philosopher.EATING: image = philImages[5]; deadlock = false; break; } g.drawImage( image, x, y, this ); }
           // draw forks
           for ( int i = 0; i < nphils; i++ ) {
               Image image = forkImages[0];
               if ( forks[i].taken() ) image = forkImages[1];
               else deadlock = false;
               int x = (int) (radius + 70 + (radius+15) 
                       * Math.cos(2*Math.PI*(i)/nphils))-15;
               int y = (int) (radius + 70 + (radius+15) 
                       * Math.sin(2*Math.PI*(i)/nphils))-15;    
               g.drawImage( image, x, y , this );
           }
           // draw table
           Image image = tableImages[0];
           g.drawImage( image, radius, radius, this );

           // Check deadlock
           if (deadlock) 
           {
               g.setColor(new Color(255,0,0));
               g.setFont(new Font("ARIAL",Font.BOLD,30));
               g.drawString( "DEADLOCK",radius-15,radius+80);
           } 
           else
           {
               // Schedule repaint applet
               try { Thread.sleep( 100 ); }
               catch ( InterruptedException e ) {}
               repaint();
           }
       }
   }
}



[Contents] [Next] [Previous]