// File: Race10.java (Module 12) // // Author: Rahul Simha // Created: Nov 17, 1998 // // Waiting and notification without deadlock: a cleaner version. import java.awt.*; import java.awt.event.*; class NewFrame extends Frame { Canvas c; public NewFrame () { // Frame properties. this.setTitle ("Dog Race"); this.setBackground (Color.cyan); this.setResizable (true); this.setSize (600,200); // Quit button. Panel p = new Panel (); Button quitb = new Button ("QUIT"); quitb.addActionListener ( new ActionListener () { public void actionPerformed (ActionEvent a) { System.exit (0); } } ); p.add (quitb); // Pressing "start" calls race() Button startb = new Button ("START"); startb.addActionListener ( new ActionListener () { public void actionPerformed (ActionEvent a) { race (); } } ); p.add (startb); this.add (p, BorderLayout.SOUTH); // A canvas to draw the results. c = new Canvas(); c.setBackground (Color.white); this.add (c, BorderLayout.CENTER); this.setVisible (true); } void race () { Dimension D = c.getSize (); // Finish-line is at the right end of the canvas. int finish_line = D.width; // Create the dog monitor. DogMonitor monitor = new DogMonitor (2); // Create two dog instances with different ID's. Dog d1 = new Dog (1, c, monitor, 2); Dog d2 = new Dog (2, c, monitor, 1); // Create a Thread instance for each dog. // Note: the class Dog must implement the // Runnable interface. Thread d1_thread = new Thread (d1); Thread d2_thread = new Thread (d2); // Start running the threads. // ("start" is a method in Thread). d1_thread.start(); d2_thread.start(); } } class DogMonitor { int[] position; boolean[] is_waiting; int num_dogs; public DogMonitor (int num_dogs) { this.num_dogs = num_dogs; position = new int [num_dogs+1]; for (int i=1; i<=num_dogs; i++) position[i] = 20; is_waiting = new boolean [num_dogs+1]; for (int i=1; i<=num_dogs; i++) is_waiting [i] = false; } // Set the new position of Dog# ID. public synchronized void set_position (int ID, int new_position) { position[ID] = new_position; } // Get the current position of Dog# ID. public synchronized int get_position (int ID) { return position[ID]; } // Before waiting, make sure no-one else waits. public synchronized void synch_wait (int ID) { boolean someone_waiting = false; for (int i=1; i<=num_dogs; i++) if (is_waiting[i]) { System.out.println ("synch_wait: i=" + i + " is waiting"); someone_waiting= true; } if (someone_waiting) { notifyAll(); for (int i=1; i<=num_dogs; i++) is_waiting[i] = false; } try { is_waiting[ID] = true; System.out.println ("ID=" + ID + " waiting"); wait (); } catch (InterruptedException e) { System.out.println (e); } } public synchronized void synch_notify (int ID) { System.out.println ("ID=" + ID + " notifying"); notify (); } } class Dog implements Runnable { int ID; // An ID. Canvas c; // The canvas on which to draw. DogMonitor monitor; // Store a reference to the monitor. int OtherID; // ID of the other dog. public Dog (int ID, Canvas c, DogMonitor monitor, int OtherID) { this.ID = ID; this.c = c; this.monitor = monitor; this.OtherID = OtherID; // Draw ID on canvas. Graphics g = c.getGraphics (); g.drawString (""+ID, 5, 20*ID+8); } public void move () { // Move a random amount. int position = monitor.get_position (ID); int new_position = position + (int) UniformRandom.uniform (1,50); monitor.set_position (ID, new_position); // Draw new position. Graphics g = c.getGraphics (); int size = new_position - position; g.fillRect (position, 20*ID, size, 10); } public void run () { // Compute the finish line distance. int finish_line = c.getSize().width; // While not complete... while (monitor.get_position (ID) < finish_line) { try { Thread.sleep ((int)UniformRandom.uniform (300,600)); } catch (InterruptedException e) { System.out.println (e); } move (); // Check if you need to wait. if (monitor.get_position (ID) - monitor.get_position (OtherID) > 20) { monitor.synch_wait (ID); } // See if the other guy is waiting for me. if (monitor.get_position (OtherID) - monitor.get_position (ID) <= 20) { monitor.synch_notify(ID); } } // endwhile } } public class Race11 { public static void main (String[] argv) { NewFrame nf = new NewFrame (); } }