// File: IO2.java // // Author: Rahul Simha // Created: Nov 18, 1998 // // Concurrent Producer-Consumer. import java.awt.*; import java.awt.event.*; import java.io.*; class Producer extends Frame implements Runnable { Label L; // A place to write stuff. Buffer buf; // Reference to the buffer. public Producer (Buffer buf) { // Store the reference to the buffer. this.buf = buf; // Create the frame. this.setSize (600,100); this.setLocation (0,100); this.setTitle ("Producer"); this.setBackground (Color.white); // this.setLayout (new BorderLayout()); // This is where we will write to. L = new Label (""); this.add (L, BorderLayout.CENTER); this.setVisible (true); } // Must implement the run() method. public void run () { // Write 25 random bytes to the buffer. for (int i=1; i<=25; i++) { // Create a random byte byte k = (byte) UniformRandom.uniform (1, 100); // Write to label first. L.setText (L.getText() + " " + k); // Write it to the screen. System.out.println ("Producer: writing " + k); // Write integer to buffer. buf.write_byte (k); // Sleep for a while. try { Thread.sleep ((int)UniformRandom.uniform(100,1000)); } catch (InterruptedException e) { System.out.println (e); } } buf.write_byte ((byte)-1); L.setText (L.getText() + " Done!"); } } class Consumer extends Frame implements Runnable { Label L; // Data similar to Producer. Buffer buf; public Consumer (Buffer buf) { this.buf = buf; this.setSize (600,100); this.setLocation (0, 200); this.setTitle ("Consumer"); this.setBackground (Color.white); // this.setLayout (new BorderLayout()); L = new Label (""); this.add (L, BorderLayout.CENTER); this.setVisible (true); } public void run () { // Read byte values until EOF. while (true) { // Get the next byte byte k = buf.read_byte (); // Check if end-of-data. if (k < 0) break; System.out.println ("Consumer: just read " + k); // Write it on the frame. L.setText (L.getText() + " " + k); // Sleep for a while. try { Thread.sleep ((int)UniformRandom.uniform(500,1000)); } catch (InterruptedException e) { System.out.println (e); } } L.setText (L.getText() + " Done!"); } } // A buffer written as a monitor. class Buffer { byte[] buf; // The buffer. int write_cursor = 0; // Pointer to last written entry. int read_cursor = 0; // Pointer to last read entry. boolean consumer_waiting =false; // A waiting flag. public Buffer () { // Allocate space. buf = new byte[1000]; } public synchronized void write_byte (byte x) { // Write to next available space. buf [++write_cursor] = x; // If consumer was waiting, notify. if (consumer_waiting) notify (); } public synchronized byte read_byte () { // If there isn't enough to read, wait. if (read_cursor == write_cursor) { consumer_waiting = true; try { wait (); } catch (InterruptedException e) { System.out.println (e); } consumer_waiting = false; } // Now read next value. byte k = buf [++read_cursor]; return k; } } // This is an independent quit button to quit the application. class QuitButton extends Frame { public QuitButton () { this.setSize (80,50); this.setLocation (0, 0); this.setTitle ("Quit button"); Button quitb = new Button ("QUIT"); quitb.setBackground (Color.red); quitb.addActionListener ( new ActionListener () { public void actionPerformed (ActionEvent a) { System.exit (0); } } ); this.add (quitb, BorderLayout.CENTER); this.setVisible (true); } } public class IO2 { public static void main (String[] argv) { // Create an independent quit button. QuitButton q = new QuitButton (); // A buffer instance. Buffer buf = new Buffer (); // Create a producer instance and thread. Producer p = new Producer (buf); Thread pthread = new Thread (p); // Create a consumer instance and thread. Consumer c = new Consumer (buf); Thread cthread = new Thread (c); // Start the threads. pthread.start(); cthread.start(); } }