| Threading becomes tricky when threads perform operations 
              that can conflict with each other. For example, say that we face 
              the following situation.  An object of class Filler 
              wants to put a number into the Cavity 
              attribute of an instance of class Box. 
              It can only do this when the cavity is empty.
 Class 
              Getter wants to retrieve the number from Cavity 
              and then leave the Cavity 
              empty.  Ideally, Filler 
              and Getter 
              would alternate their calls to the methods put() 
              and get(). 
             However, if no special steps are taken, it is quite 
              easy for Getter 
              to call get() 
              when the Cavity 
              is empty and for Filler 
              to call put() 
              when the Cavity 
              is still full. This type of situation is called a data race 
              because each thread is racing to do its task without waiting for 
              the other thread to finish its activity.  A synchronization scheme is used to prevent 
              this problem. The solution is to make the threads wait in single 
              file at the method or code block where the conflict can occur.  In the case above, this means that an instance 
              of Box only 
              allows one thread at a time to invoke its put() 
              or get(). It is as if only one thread object owns the key 
              to the lock on the doors to Box. 
              It must give up the key (though by tradition you say that the thread 
              gives up the lock) before any other thread can access a synchronized 
              method on the object.   
              Note that each instance has its 
                own lock. There is no interference problem among different instances 
                of Box. 
                A lock on one instance has no affect on access to put() 
                and get()on 
                another instance of box. Synchronized Methods When a process invokes put() 
              or get(), 
              which have the synchronized 
              modifier, for an instance of the Box 
              class below, it will wait until it is granted the lock for that 
              object. The process continues through the method. However, if a 
              flag is not set it will invoke the wait() 
              method. This allows the process to give up the lock and remain at 
              that point in the computation until a notifyAll() 
               method is called.  The notifyAll() 
              will wake up all the currently waiting threads and check if they 
              can have the lock for this particular object. If one process gets 
              the lock then it proceeds though the method and then invokes notifyAll(), 
              which will wake up any other waiting threads.   
              
                 
                  | ExclusiveApplet.java + Box.java 
                    + Getter.java 
                    + Filler.java
 + Outputable.java
 |   
                  |  import 
                      javax.swing.*;import java.awt.*;
 import java.awt.event.*;
 
 /**
 * This demo applet illustrates synchronization 
                      with the
 * Filler thread trying to fill the bin in the 
                      Box object
 * and the Getter thread trying to get the value 
                      from the
 * bin. The Filler must wait if the bin already 
                      is full while
 * the getter must wait if it is empty.
 *
 * Output of the thread goes to the text area 
                      on the applet
 * interface. The applet implements the Outputable 
                      interface.
 *
 * Derived from Java Tutorial Cubbyhole/Producer 
                      example.
 **/
 public class ExclusiveApplet extends JApplet
 implements Outputable, ActionListener
 {
 // A Swing textarea for display of string info
 JTextArea fTextArea = null;
 
 /**
 * Create a User Interface with a 
                      textarea with sroll bars
 * and a Go button to initiate processing 
                      and a Clear button
 * to clear the textarea.
 **/
 public void init  () {
 Container content_pane = getContentPane  ();
 JPanel panel = new JPanel  (new 
                      BorderLayout  ());
 
 // Create a text area.
 fTextArea = new JTextArea  ();
 
 // Make it editable
 fTextArea.setEditable  (false);
 
 // Add to a scroll pane so that 
                      a long list of
 // computations can be seen.
 JScrollPane area_scroll_pane = new 
                      JScrollPane  (fTextArea);
 
 panel.add  (area_scroll_pane,BorderLayout.CENTER);
 
 JButton go_button = new JButton  ("Go");
 go_button.addActionListener  (this);
 
 JButton clear_button = new JButton  ("Clear");
 clear_button.addActionListener  (this);
 
 JPanel control_panel = new JPanel  ();
 control_panel.add  (go_button);
 control_panel.add  (clear_button);
 
 panel.add  (control_panel,BorderLayout.SOUTH);
 
 // Add text area & control panel.
 content_pane.add  (panel);
 } // init
 
 /** Respond to the buttons to start the threads 
                      or to clear
 * the text area.
 **/
 public void actionPerformed  (ActionEvent 
                      e) {
 if  ( e.getActionCommand  ().equals  ("Go"))
 start  ();
 else
 fTextArea.setText  (null);
 } // actionPerformed
 
 /** Create Filler and Getter thread instances 
                      and
 * start them filling and getting 
                      from a Box instance.
 **/
 public void start () {
 Box b = new Box (this);
 Filler f1 = new Filler (b);
 Getter b1 = new Getter (b);
 
 f1.start ();
 b1.start ();
 } // start
 
 /** Overided Outputable println to send string 
                      to text area.**/
 public void println  (String str)  {
 fTextArea.append  (str 
                      + CR);
 }
 
 /** Overided Outputable print to send string 
                      to text area.**/
 public void print  (String str) {
 fTextArea.append  (str);
 }
 
 }// class ExclusiveApplet
 |   
                  | /*** Use synchronized methods to "put" and "fill"
 * a bin, which holds some number passed to it.
 * A flag indicates whether the bin is in a filled 
                      state
 * or not.
 
 * The put method goes into wait state if bin 
                      is filled.
 * Similarly, the get method waits if bin not 
                      filled.
 * When they emerge from the wait states, the 
                      processes
 * do their given tasks and then invoke notifyAll 
                      () to
 * wake up other threads that might be waiting 
                      on the
 * object.
 
 *
 **/
 public class Box {
 private int fBin;
 private boolean fFilled = false;
 Outputable fOut;
 
 /** Constructor obtains reference to Outputable 
                      object.**/
 Box (Outputable out){
 fOut = out;
 }
 
 /**
 * If bin is not filled, wait for 
                      it to be.
 * If bin filled, then empty it  (i.e. 
                      set flag to false.)
 * Notify other waiting threads that 
                      are in wait state
 * on this object. Return the value 
                      in the bin.
 **/
 public synchronized int get () {
 while  (fFilled == false){
 try {
 wait ();
 }
 catch  (InterruptedException 
                      e) { }
 }
 fFilled = false;
 fOut.println ("Get value: " + fBin);
 notifyAll ();
 return fBin;
 } // get
 
 /**
 * If bin is filled, wait for it 
                      to be emptied.
 * If bin not filled, then fill it  (i.e. 
                      set flag to true.)
 * Notify other waiting threads that 
                      are in wait state
 * on this object.
 **/
 public synchronized void put (int value){
 while  (fFilled == true) 
                      {
 try  {
 wait ();
 } catch  (InterruptedException 
                      e)  { }
 }
 fBin = value;
 fFilled = true;
 fOut.println ("Put value: " + fBin);
 notifyAll ();
 } // put
 
 } // class Box
 
 |   
                  |  /** Retrieve 
                      the value from the Box object.**/public class Getter extends Thread {
 private Box fBox;
 private int fNumber;
 
 public Getter (Box b) {
 fBox = b;
 } // ctor
 
 public void run () {
 for (int i = 0; i < 10; i++) {
 fNumber 
                      = fBox.get ();
 }
 } // run
 
 } // class Getter
 |   
                  | /*** A thread to fill the bin in the Box object.
 * Derived from Java Tutorial Cubbyhole/Producer 
                      example
 **/
 public class Filler extends Thread {
 private Box fBox;
 
 public Filler (Box b) {
 fBox = b;
 } // ctor
 
 public void run () {
 for  (int i=0; i<10; i++){
 fBox.put (i);
 try {
 sleep 
                      ( (int) (Math.random () * 100));
 }
 catch  (InterruptedException 
                      e) { }
 }
 } // run
 
 } // class Filler
 |    The output of this program shows that the filler and 
              getter threads do not get into a data race.  References & Web Resources Latest update: Nov. 6, 2004 |