Concurrent Programming with Java
Lab Manual, Version 1.0, F. Astha Ekadiyanto,
2002.
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) // 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(); } } } } |