James Thornton logo
James Thornton
Google
Web jamesthornton.com
Internet Business Consultant Call Toll Free: 1 (800) 409-2501
About James My MySpace Internet Marketing Enron Loophole Lock Bumping Contact Me
JamesThornton.com -> Bruce Eckel Books -> TIJ-2nd-edition -> One Page

MindView Inc.
[ Viewing Hints ] [ Revision History ] [ Book Home Page ] [ Free Newsletter ]
[ Seminars ] [ Seminars on CD ROM ] [ Consulting ]

Thinking in Java, 2nd edition, Revision 12

©2000 by Bruce Eckel

[ Previous Chapter ] [ Short TOC ] [ Table of Contents ] [ Index ] [ Next Chapter ]

14: Multiple Threads

Objects provide a way to divide a program into independent sections. Often, you also need to turn a program into separate, independently running subtasks.

Each of these independent subtasks is called a thread, and you program as if each thread runs by itself and has the CPU to itself. Some underlying mechanism is actually dividing up the CPU time for you, but in general, you don’t have to think about it, which makes programming with multiple threads a much easier task. [ Add Comment ]

A process is a self-contained running program with its own address space. A multitasking operating system is capable of running more than one process (program) at a time, while making it look like each one is chugging along on its own, by periodically providing CPU cycles to each process. A thread is a single sequential flow of control within a process. A single process can thus have multiple concurrently executing threads. [ Add Comment ]

There are many possible uses for multithreading, but in general, you’ll have some part of your program tied to a particular event or resource, and you don’t want to hang up the rest of your program because of that. So you create a thread associated with that event or resource and let it run independently of the main program. A good example is a “quit” button—you don’t want to be forced to poll the quit button in every piece of code you write in your program and yet you want the quit button to be responsive, as if you were checking it regularly. In fact, one of the most immediately compelling reasons for multithreading is to produce a responsive user interface. [ Add Comment ]

Responsive user interfaces

As a starting point, consider a program that performs some CPU-intensive operation and thus ends up ignoring user input and being unresponsive. This one, a combined applet/application, will simply display the result of a running counter:

//: c14:Counter1.java
// A non-responsive user interface.
// <applet code=Counter1 width=300 height=100>
// </applet>
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
import com.bruceeckel.swing.*;

public class Counter1 extends JApplet {
  private int count = 0;
  private JButton
    start = new JButton("Start"),
    onOff = new JButton("Toggle");
  private JTextField t = new JTextField(10);
  private boolean runFlag = true;
  public void init() {
    Container cp = getContentPane();
    cp.setLayout(new FlowLayout());
    cp.add(t);
    start.addActionListener(new StartL());
    cp.add(start);
    onOff.addActionListener(new OnOffL());
    cp.add(onOff);
  }
  public void go() {
    while (true) {
      try {
        Thread.sleep(100);
      } catch(InterruptedException e) {
        System.err.println("Interrupted");
      }
      if (runFlag)
        t.setText(Integer.toString(count++));
    }
  }
  class StartL implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      go();
    }
  }
  class OnOffL implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      runFlag = !runFlag;
    }
  }
  public static void main(String[] args) {
    Console.run(new Counter1(), 300, 100);
  }
} ///:~

At this point, the Swing and applet code should be reasonably familiar from Chapter 13. The go( ) method is where the program stays busy: it puts the current value of count into the JTextField t, then increments count. [ Add Comment ]

Part of the infinite loop inside go( ) is to call sleep( ). sleep( ) must be associated with a Thread object, and it turns out that every application has some thread associated with it. (Indeed, Java is based on threads and there are always some running along with your application.) So regardless of whether you’re explicitly using threads, you can produce the current thread used by your program with Thread and the static sleep( ) method. [ Add Comment ]

Note that sleep( ) can throw an InterruptedException, although throwing such an exception is considered a hostile way to break from a thread and should be discouraged. (Once again, exceptions are for exceptional conditions, not normal flow of control.) Interrupting a sleeping thread is included to support a future language feature. [ Add Comment ]

When the start button is pressed, go( ) is invoked. On examining go( ), you might naively think (as I did) that it should allow multithreading because it goes to sleep. That is, while the method is asleep, it seems like the CPU could be busy monitoring other button presses. But it turns out that the real problem is that go( ) never returns, since it’s in an infinite loop, and this means that actionPerformed( ) never returns. Since you’re stuck inside actionPerformed( ) for the first keypress, the program can’t handle any other events. (To get out, you must somehow kill the process; the easiest way to do this is to press Control-C in the console window, if you started it from the console. If you start it via the browser, you have to kill the browser window.) [ Add Comment ]

The basic problem here is that go( ) needs to continue performing its operations, and at the same time it needs to return so that actionPerformed( ) can complete and the user interface can continue responding to the user. But in a conventional method like go( ) it cannot continue and at the same time return control to the rest of the program. This sounds like an impossible thing to accomplish, as if the CPU must be in two places at once, but this is precisely the illusion that threading provides. [ Add Comment ]

The thread model (and its programming support in Java) is a programming convenience to simplify juggling several operations at the same time within a single program. With threads, the CPU will pop around and give each thread some of its time. Each thread has the consciousness of constantly having the CPU to itself, but the CPU’s time is actually sliced between all the threads. The exception to this is if your program is running on multiple CPUs. But one of the great things about threading is that you are abstracted away from this layer, so your code does not need to know whether it is actually running on a single CPU or many. Thus, threads are a way to create transparently scalable programs. [ Add Comment ]

Threading reduces computing efficiency somewhat, but the net improvement in program design, resource balancing, and user convenience is often quite valuable. Of course, if you have more than one CPU, then the operating system can dedicate each CPU to a set of threads or even a single thread and the whole program can run much faster. Multitasking and multithreading tend to be the most reasonable ways to utilize multiprocessor systems. [ Add Comment ]

Inheriting from Thread

The simplest way to create a thread is to inherit from class Thread, which has all the wiring necessary to create and run threads. The most important method for Thread is run( ), which you must override to make the thread do your bidding. Thus, run( ) is the code that will be executed “simultaneously” with the other threads in a program. [ Add Comment ]

The following example creates any number of threads that it keeps track of by assigning each thread a unique number, generated with a static variable. The Thread’s run( ) method is overridden to count down each time it passes through its loop and to finish when the count is zero (at the point when run( ) returns, the thread is terminated).

//: c14:SimpleThread.java
// Very simple Threading example.

public class SimpleThread extends Thread {
  private int countDown = 5;
  private static int threadCount = 0;
  private int threadNumber = ++threadCount;
  public SimpleThread() {
    System.out.println("Making " + threadNumber);
  }
  public void run() {
    while(true) {
      System.out.println("Thread " + 
        threadNumber + "(" + countDown + ")");
      if(--countDown == 0) return;
    }
  }
  public static void main(String[] args) {
    for(int i = 0; i < 5; i++)
      new SimpleThread().start();
    System.out.println("All Threads Started");
  }
} ///:~

A run( ) method virtually always has some kind of loop that continues until the thread is no longer necessary, so you must establish the condition on which to break out of this loop (or, in the case above, simply return from run( )). Often, run( ) is cast in the form of an infinite loop, which means that, barring some external factor that causes run( ) to terminate, it will continue forever. [ Add Comment ]

In main( ) you can see a number of threads being created and run. The start( ) method in the Thread class performs special initialization for the thread and then calls run( ). So the steps are: the constructor is called to build the object, then start( ) configures the thread and calls run( ). If you don’t call start( ) (which you can do in the constructor, if that’s appropriate) the thread will never be started. [ Add Comment ]

The output for one run of this program (it will be different from one run to another) is:

Making 1
Making 2
Making 3
Making 4
Making 5
Thread 1(5)
Thread 1(4)
Thread 1(3)
Thread 1(2)
Thread 2(5)
Thread 2(4)
Thread 2(3)
Thread 2(2)
Thread 2(1)
Thread 1(1)
All Threads Started
Thread 3(5)
Thread 4(5)
Thread 4(4)
Thread 4(3)
Thread 4(2)
Thread 4(1)
Thread 5(5)
Thread 5(4)
Thread 5(3)
Thread 5(2)
Thread 5(1)
Thread 3(4)
Thread 3(3)
Thread 3(2)
Thread 3(1)

You’ll notice that nowhere in this example is sleep( ) called, and yet the output indicates that each thread gets a portion of the CPU’s time in which to execute. This shows that sleep( ), while it relies on the existence of a thread in order to execute, is not involved with either enabling or disabling threading. It’s simply another method. [ Add Comment ]

You can also see that the threads are not run in the order that they’re created. In fact, the order that the CPU attends to an existing set of threads is indeterminate, unless you go in and adjust the priorities using Thread’s setPriority( ) method. [ Add Comment ]

When main( ) creates the Thread objects it isn’t capturing the references for any of them. An ordinary object would be fair game for garbage collection, but not a Thread. Each Thread “registers” itself so there is actually a reference to it someplace and the garbage collector can’t clean it up. [ Add Comment ]

Threading for a responsive interface

Now it’s possible to solve the problem in Counter1.java with a thread. The trick is to place the subtask—that is, the loop that’s inside go( )—inside the run( ) method of a thread. When the user presses the start button, the thread is started, but then the creation of the thread completes, so even though the thread is running, the main job of the program (watching for and responding to user-interface events) can continue. Here’s the solution:

//: c14:Counter2.java
// A responsive user interface with threads.
// <applet code=Counter2 width=300 height=100>
// </applet>
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import com.bruceeckel.swing.*;

public class Counter2 extends JApplet {
  private class SeparateSubTask extends Thread {
    private int count = 0;
    private boolean runFlag = true;
    SeparateSubTask() { start(); }
    void invertFlag() { runFlag = !runFlag; }
    public void run() {
      while (true) {
       try {
        sleep(100);
      } catch(InterruptedException e) {
        System.err.println("Interrupted");
      }
       if(runFlag) 
         t.setText(Integer.toString(count++));
      }
    }
  } 
  private SeparateSubTask sp = null;
  private JTextField t = new JTextField(10);
  private JButton 
    start = new JButton("Start"),
    onOff = new JButton("Toggle");
  class StartL implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      if(sp == null)
        sp = new SeparateSubTask();
    }
  }
  class OnOffL implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      if(sp != null)
        sp.invertFlag();
    }
  }
  public void init() {
    Container cp = getContentPane();
    cp.setLayout(new FlowLayout());
    cp.add(t);
    start.addActionListener(new StartL());
    cp.add(start);
    onOff.addActionListener(new OnOffL());
    cp.add(onOff);
  }
  public static void main(String[] args) {
    Console.run(new Counter2 (), 300, 100);
  }
} ///:~

Counter2 is a straightforward program, whose only job is to set up and maintain the user interface. But now, when the user presses the start button, the event-handling code does not call a method. Instead a thread of class SeparateSubTask is created, and then the Counter2 event loop continues. [ Add Comment ]

The class SeparateSubTask is a simple extension of Thread with a constructor that runs the thread by calling start( ), and a run( ) that essentially contains the “go( )” code from Counter1.java. [ Add Comment ]

Because SeparateSubTask is an inner class, it can directly access the JTextField t in Counter2; you can see this happening inside run( ). The t field in the outer class is private since SeparateSubTask can access it without getting any special permission—and it’s always good to make fields “as private as possible” so they cannot be accidentally changed by forces outside your class. [ Add Comment ]

When you press the onOff button it toggles the runFlag inside the SeparateSubTask object. That thread (when it looks at the flag) can then start and stop itself. Pressing the onOff button produces an apparently instant response. Of course, the response isn’t really instant, not like that of a system that’s driven by interrupts. The counter stops only when the thread has the CPU and notices that the flag has changed. [ Add Comment ]

You can see that the inner class SeparateSubTask is private, which means that its fields and methods can be given default access (except for run( ), which must be public since it is public in the base class). The private inner class is not accessible to anyone but Counter2, and the two classes are tightly coupled. Anytime you notice classes that appear to have high coupling with each other, consider the coding and maintenance improvements you might get by using inner classes. [ Add Comment ]

Combining the thread
with the main class

In the example above you can see that the thread class is separate from the program’s main class. This makes a lot of sense and is relatively easy to understand. There is, however, an alternate form that you will often see used that is not so clear but is usually more concise (which probably accounts for its popularity). This form combines the main program class with the thread class by making the main program class a thread. Since for a GUI program the main program class must be inherited from either Frame or Applet, an interface must be used to paste on the additional functionality. This interface is called Runnable, and it contains the same basic method that Thread does. In fact, Thread also implements Runnable, which specifies only that there be a run( ) method. [ Add Comment ]

The use of the combined program/thread is not quite so obvious. When you start the program, you create an object that’s Runnable, but you don’t start the thread. This must be done explicitly. You can see this in the following program, which reproduces the functionality of Counter2:

//: c14:Counter3.java
// Using the Runnable interface to turn the 
// main class into a thread.
// <applet code=Counter3 width=300 height=100>
// </applet>
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import com.bruceeckel.swing.*;

public class Counter3 
    extends JApplet implements Runnable {
  private int count = 0;
  private boolean runFlag = true;
  private Thread selfThread = null;
  private JButton 
    start = new JButton("Start"),
    onOff = new JButton("Toggle");
  private JTextField t = new JTextField(10);
  public void run() {
    while (true) {
      try {
        selfThread.sleep(100);
      } catch(InterruptedException e) {
        System.err.println("Interrupted");
      }
      if(runFlag) 
        t.setText(Integer.toString(count++));
    }
  }
  class StartL implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      if(selfThread == null) {
        selfThread = new Thread(Counter3.this);
        selfThread.start();
      }
    }
  }
  class OnOffL implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      runFlag = !runFlag;
    }
  }
  public void init() {
    Container cp = getContentPane();
    cp.setLayout(new FlowLayout());
    cp.add(t);
    start.addActionListener(new StartL());
    cp.add(start);
    onOff.addActionListener(new OnOffL());
    cp.add(onOff);
  }
  public static void main(String[] args) {
    Console.run(new Counter3(), 300, 100);
  }
} ///:~

Now the run( ) is inside the class, but it’s still dormant after init( ) completes. When you press the start button, the thread is created (if it doesn’t already exist) in the somewhat obscure expression: [ Add Comment ]

new Thread(Counter3.this);

When something has a Runnable interface, it simply means that it has a run( ) method, but there’s nothing special about that—it doesn’t produce any innate threading abilities, like those of a class inherited from Thread. So to produce a thread from a Runnable object, you must create a separate Thread object as shown above, handing the Runnable object to the special Thread constructor. You can then call start( ) for that thread: [ Add Comment ]

selfThread.start();

This performs the usual initialization and then calls run( ). [ Add Comment ]

The convenient aspect about the Runnable interface is that everything belongs to the same class. If you need to access something, you simply do it without going through a separate object. However, as you saw in the previous example, this access is just as easy using an inner class[70]. [ Add Comment ]

Making many threads

Consider the creation of many different threads. You can’t do this with the previous example, so you must go back to having separate classes inherited from Thread to encapsulate the run( ). But this is a more general solution and easier to understand, so while the previous example shows a coding style you’ll often see, I can’t recommend it for most cases because it’s just a little bit more confusing and less flexible. [ Add Comment ]

The following example repeats the form of the examples above with counters and toggle buttons. But now all the information for a particular counter, including the button and text field, is inside its own object that is inherited from Thread. All the fields in Ticker are private, which means that the Ticker implementation can be changed at will, including the quantity and type of data components to acquire and display information. When a Ticker object is created, the constructor adds its visual components to the content pane of the outer object:

//: c14:Counter4.java
// By keeping your thread as a distinct class,
// you can have as many threads as you want. 
// <applet code=Counter4 width=200 height=600>
// <param name=size value="12"></applet>
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import com.bruceeckel.swing.*;

public class Counter4 extends JApplet {
  private JButton start = new JButton("Start");
  private boolean started = false;
  private Ticker[] s;
  private boolean isApplet = true;
  private int size = 12;
  class Ticker extends Thread {
    private JButton b = new JButton("Toggle");
    private JTextField t = new JTextField(10);
    private int count = 0;
    private boolean runFlag = true;
    public Ticker() {
      b.addActionListener(new ToggleL());
      JPanel p = new JPanel();
      p.add(t);
      p.add(b);
      // Calls JApplet.getContentPane().add():
      getContentPane().add(p); 
    }
    class ToggleL implements ActionListener {
      public void actionPerformed(ActionEvent e) {
        runFlag = !runFlag;
      }
    }
    public void run() {
      while (true) {
        if (runFlag)
          t.setText(Integer.toString(count++));
        try {
          sleep(100);
        } catch(InterruptedException e) {
          System.err.println("Interrupted");
        }
      }
    }
  }
  class StartL implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      if(!started) {
        started = true;
        for (int i = 0; i < s.length; i++)
          s[i].start();
      }
    }
  }
  public void init() {
    Container cp = getContentPane();
    cp.setLayout(new FlowLayout());
    // Get parameter "size" from Web page:
    if (isApplet) {
      String sz = getParameter("size");
      if(sz != null)
        size = Integer.parseInt(sz);
    }
    s = new Ticker[size];
    for (int i = 0; i < s.length; i++)
      s[i] = new Ticker();
    start.addActionListener(new StartL());
    cp.add(start);
  }
  public static void main(String[] args) {
    Counter4 applet = new Counter4();
    // This isn't an applet, so set the flag and
    // produce the parameter values from args:
    applet.isApplet = false;
    if(args.length != 0)
      applet.size = Integer.parseInt(args[0]);
    Console.run(applet, 200, applet.size * 50);
  }
} ///:~

Ticker contains not only its threading equipment but also the way to control and display the thread. You can create as many threads as you want without explicitly creating the windowing components. [ Add Comment ]

In Counter4 there’s an array of Ticker objects called s. For maximum flexibility, the size of this array is initialized by reaching out into the Web page using applet parameters. Here’s what the size parameter looks like on the page, embedded inside the applet tag:

<param name=size value="20">

The param, name, and value are all HTML keywords. name is what you’ll be referring to in your program, and value can be any string, not just something that resolves to a number. [ Add Comment ]

You’ll notice that the determination of the size of the array s is done inside init( ), and not as part of an inline definition of s. That is, you cannot say as part of the class definition (outside of any methods):

int size = Integer.parseInt(getParameter("size"));
Ticker[] s = new Ticker[size];

You can compile this, but you’ll get a strange “null-pointer exception” at run-time. It works fine if you move the getParameter( ) initialization inside of init( ). The applet framework performs the necessary startup to grab the parameters before entering init( ). [ Add Comment ]

In addition, this code is set up to be either an applet or an application. When it’s an application the size argument is extracted from the command line (or a default value is provided). [ Add Comment ]

Once the size of the array is established, new Ticker objects are created; as part of the Ticker constructor the button and text field for each Ticker is added to the applet. [ Add Comment ]

Pressing the start button means looping through the entire array of Tickers and calling start( ) for each one. Remember, start( ) performs necessary thread initialization and then calls run( ) for that thread. [ Add Comment ]

The ToggleL listener simply inverts the flag in Ticker and when the associated thread next takes note it can react accordingly. [ Add Comment ]

One value of this example is that it allows you to easily create large sets of independent subtasks and to monitor their behavior. In this case, you’ll see that as the number of subtasks gets larger, your machine will probably show more divergence in the displayed numbers because of the way that the threads are served. [ Add Comment ]

You can also experiment to discover how important the sleep(100) is inside Ticker.run( ). If you remove the sleep( ), things will work fine until you press a toggle button. Then that particular thread has a false runFlag and the run( ) is just tied up in a tight infinite loop, which appears difficult to break during multithreading, so the responsiveness and speed of the program really bogs down. [ Add Comment ]

Daemon threads

A “daemon” thread is one that is supposed to provide a general service in the background as long as the program is running, but is not part of the essence of the program. Thus, when all of the non-daemon threads complete, the program is terminated. Conversely, if there are any non-daemon threads still running, the program doesn’t terminate. (There is, for instance, a thread that runs main( ).) [ Add Comment ]

You can find out if a thread is a daemon by calling isDaemon( ), and you can turn the “daemonhood” of a thread on and off with setDaemon( ). If a thread is a daemon, then any threads it creates will automatically be daemons. [ Add Comment ]

The following example demonstrates daemon threads:

//: c14:Daemons.java
// Daemonic behavior.
import java.io.*;

class Daemon extends Thread {
  private static final int SIZE = 10;
  private Thread[] t = new Thread[SIZE];
  public Daemon() { 
    setDaemon(true);
    start();
  }
  public void run() {
    for(int i = 0; i < SIZE; i++)
      t[i] = new DaemonSpawn(i);
    for(int i = 0; i < SIZE; i++)
      System.out.println(
        "t[" + i + "].isDaemon() = " 
        + t[i].isDaemon());
    while(true) 
      yield();
  }
}

class DaemonSpawn extends Thread {
  public DaemonSpawn(int i) {
    System.out.println(
      "DaemonSpawn " + i + " started");
    start();
  }
  public void run() {
    while(true) 
      yield();
  }
}

public class Daemons {
  public static void main(String[] args) 
  throws IOException {
    Thread d = new Daemon();
    System.out.println(
      "d.isDaemon() = " + d.isDaemon());
    // Allow the daemon threads to
    // finish their startup processes:
    System.out.println("Press any key");
    System.in.read();
  }
} ///:~

The Daemon thread sets its daemon flag to “true” and then spawns a bunch of other threads to show that they are also daemons. Then it goes into an infinite loop that calls yield( ) to give up control to the other processes. In an earlier version of this program, the infinite loops would increment int counters, but this seemed to bring the whole program to a stop. Using yield( ) makes the program quite peppy. [ Add Comment ]

There’s nothing to keep the program from terminating once main( ) finishes its job, since there are nothing but daemon threads running. So that you can see the results of starting all the daemon threads, System.in is set up to read so the program waits for a keypress before terminating. Without this you see only some of the results from the creation of the daemon threads. (Try replacing the read( ) code with sleep( ) calls of various lengths to see this behavior.) [ Add Comment ]

Sharing limited resources

You can think of a single-threaded program as one lonely entity moving around through your problem space and doing one thing at a time. Because there’s only one entity, you never have to think about the problem of two entities trying to use the same resource at the same time, like two people trying to park in the same space, walk through a door at the same time, or even talk at the same time. [ Add Comment ]

With multithreading, things aren’t lonely anymore, but you now have the possibility of two or more threads trying to use the same limited resource at once. Colliding over a resource must be prevented or else you’ll have two threads trying to access the same bank account at the same time, print to the same printer, or adjust the same valve, etc. [ Add Comment ]

Improperly accessing resources

Consider a variation on the counters that have been used so far in this chapter. In the following example, each thread contains two counters that are incremented and displayed inside run( ). In addition, there’s another thread of class Watcher that is watching the counters to see if they’re always equivalent. This seems like a needless activity, since looking at the code it appears obvious that the counters will always be the same. But that’s where the surprise comes in. Here’s the first version of the program:

//: c14:Sharing1.java
// Problems with resource sharing while threading.
// <applet code=Sharing1 width=350 height=500>
// <param name=size value="12">
// <param name=watchers value="15">
// </applet>
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import com.bruceeckel.swing.*;

public class Sharing1 extends JApplet {
  private static int accessCount = 0;
  private static JTextField aCount = 
    new JTextField("0", 7);
  public static void incrementAccess() {
    accessCount++;
    aCount.setText(Integer.toString(accessCount));
  }
  private JButton 
    start = new JButton("Start"),
    watcher = new JButton("Watch");
  private boolean isApplet = true;
  private int numCounters = 12;
  private int numWatchers = 15;
  private TwoCounter[] s;
  class TwoCounter extends Thread {
    private boolean started = false;
    private JTextField 
      t1 = new JTextField(5),
      t2 = new JTextField(5);
    private JLabel l = 
      new JLabel("count1 == count2");
    private int count1 = 0, count2 = 0;
    // Add the display components as a panel:
    public TwoCounter() {
      JPanel p = new JPanel();
      p.add(t1);
      p.add(t2);
      p.add(l);
      getContentPane().add(p);
    }
    public void start() {
      if(!started) {
        started = true;
        super.start();
      }
    }
    public void run() {
      while (true) {
        t1.setText(Integer.toString(count1++));
        t2.setText(Integer.toString(count2++));
        try {
          sleep(500);
        } catch(InterruptedException e) {
          System.err.println("Interrupted");
        }
      }
    }
    public void synchTest() {
      incrementAccess();
      if(count1 != count2)
        l.setText("Unsynched");
    }
  }
  class Watcher extends Thread {
    public Watcher() { start(); }
    public void run() {
      while(true) {
        for(int i = 0; i < s.length; i++)
          s[i].synchTest();
        try {
          sleep(500);
        } catch(InterruptedException e) {
          System.err.println("Interrupted");
        }
      }
    }
  }
  class StartL implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      for(int i = 0; i < s.length; i++)
        s[i].start();
    }
  }
  class WatcherL implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      for(int i = 0; i < numWatchers; i++)
        new Watcher();
    }
  }
  public void init() {
    if(isApplet) {
      String counters = getParameter("size");
      if(counters != null)
        numCounters = Integer.parseInt(counters);
      String watchers = getParameter("watchers");
      if(watchers != null)
        numWatchers = Integer.parseInt(watchers);
    }
    s = new TwoCounter[numCounters];
    Container cp = getContentPane();
    cp.setLayout(new FlowLayout());
    for(int i = 0; i < s.length; i++)
      s[i] = new TwoCounter();
    JPanel p = new JPanel();
    start.addActionListener(new StartL());
    p.add(start);
    watcher.addActionListener(new WatcherL());
    p.add(watcher);
    p.add(new JLabel("Access Count"));
    p.add(aCount);
    cp.add(p);
  }
  public static void main(String[] args) {
    Sharing1 applet = new Sharing1();
    // This isn't an applet, so set the flag and
    // produce the parameter values from args:
    applet.isApplet = false;
    applet.numCounters = 
      (args.length == 0 ? 12 :
        Integer.parseInt(args[0]));
    applet.numWatchers =
      (args.length < 2 ? 15 :
        Integer.parseInt(args[1]));
    Console.run(applet, 350, 
      applet.numCounters * 50);
  }
} ///:~

As before, each counter contains its own display components: two text fields and a label that initially indicates that the counts are equivalent. These components are added to the content pane of the outer class object in the TwoCounter constructor. [ Add Comment ]

Because a TwoCounter thread is started via a keypress by the user, it’s possible that start( ) could be called more than once. It’s illegal for Thread.start( ) to be called more than once for a thread (an exception is thrown). You can see the machinery to prevent this in the started flag and the overridden start( ) method. [ Add Comment ]

In run( ), count1 and count2 are incremented and displayed in a manner that would seem to keep them identical. Then sleep( ) is called; without this call the program balks because it becomes hard for the CPU to swap tasks. [ Add Comment ]

The synchTest( ) method performs the apparently useless activity of checking to see if count1 is equivalent to count2; if they are not equivalent it sets the label to “Unsynched” to indicate this. But first, it calls a static member of the class Sharing1 that increments and displays an access counter to show how many times this check has occurred successfully. (The reason for this will become apparent in later variations of this example.) [ Add Comment ]

The Watcher class is a thread whose job is to call synchTest( ) for all of the TwoCounter objects that are active. It does this by stepping through the array that’s kept in the Sharing1 object. You can think of the Watcher as constantly peeking over the shoulders of the TwoCounter objects. [ Add Comment ]

Sharing1 contains an array of TwoCounter objects that it initializes in init( ) and starts as threads when you press the “start” button. Later, when you press the “Watch” button, one or more watchers are created and freed upon the unsuspecting TwoCounter threads. [ Add Comment ]

Note that to run this as an applet in a browser, your applet tag will need to contain the lines:

<param name=size value="20">
<param name=watchers value="1">

You can experiment by changing the width, height, and parameters to suit your tastes. By changing the size and watchers you’ll change the behavior of the program. This program is set up to run as a stand-alone application by pulling the arguments from the command line (or providing defaults). [ Add Comment ]

Here’s the surprising part. In TwoCounter.run( ), the infinite loop is just repeatedly passing over the adjacent lines:

t1.setText(Integer.toString(count1++));
t2.setText(Integer.toString(count2++));

(as well as sleeping, but that’s not important here). When you run the program, however, you’ll discover that count1 and count2 will be observed (by the Watchers) to be unequal at times! This is because of the nature of threads—they can be suspended at any time. So at times, the suspension occurs between the execution of the above two lines, and the Watcher thread happens to come along and perform the comparison at just this moment, thus finding the two counters to be different. [ Add Comment ]

This example shows a fundamental problem with using threads. You never know when a thread might be run. Imagine sitting at a table with a fork, about to spear the last piece of food on your plate and as your fork reaches for it, the food suddenly vanishes (because your thread was suspended and another thread came in and stole the food). That’s the problem that you’re dealing with. [ Add Comment ]

Sometimes you don’t care if a resource is being accessed at the same time you’re trying to use it (the food is on some other plate). But for multithreading to work, you need some way to prevent two threads from accessing the same resource, at least during critical periods. [ Add Comment ]

Preventing this kind of collision is simply a matter of putting a lock on a resource when one thread is using it. The first thread that accesses a resource locks it, and then the other threads cannot access that resource until it is unlocked, at which time another thread locks and uses it, etc. If the front seat of the car is the limited resource, the child who shouts “Dibs!” asserts the lock. [ Add Comment ]

How Java shares resources

Java has built-in support to prevent collisions over one kind of resource: the memory in an object. Since you typically make the data elements of a class private and access that memory only through methods, you can prevent collisions by making a particular method synchronized. Only one thread at a time can call a synchronized method for a particular object (although that thread can call more than one of the object’s synchronized methods). Here are simple synchronized methods:

synchronized void f() { /* ... */ }
synchronized void g(){ /* ... */ }

Each object contains a single lock (also called a monitor) that is automatically part of the object (you don’t have to write any special code). When you call any synchronized method, that object is locked and no other synchronized method of that object can be called until the first one finishes and releases the lock. In the example above, if f( ) is called for an object, g( ) cannot be called for the same object until f( ) is completed and releases the lock. Thus, there’s a single lock that’s shared by all the synchronized methods of a particular object, and this lock prevents common memory from being written by more than one method at a time (i.e., more than one thread at a time). [ Add Comment ]

There’s also a single lock per class (as part of the Class object for the class), so that synchronized static methods can lock each other out from simultaneous access of static data on a class-wide basis. [ Add Comment ]

Note that if you want to guard some other resource from simultaneous access by multiple threads, you can do so by forcing access to that resource through synchronized methods. [ Add Comment ]

Synchronizing the counters

Armed with this new keyword it appears that the solution is at hand: we’ll simply use the synchronized keyword for the methods in TwoCounter. The following example is the same as the previous one, with the addition of the new keyword:

//: c14:Sharing2.java
// Using the synchronized keyword to prevent
// multiple access to a particular resource.
// <applet code=Sharing2 width=350 height=500>
// <param name=size value="12">
// <param name=watchers value="15">
// </applet>
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import com.bruceeckel.swing.*;

public class Sharing2 extends JApplet {
  TwoCounter[] s;
  private static int accessCount = 0;
  private static JTextField aCount = 
    new JTextField("0", 7);
  public static void incrementAccess() {
    accessCount++;
    aCount.setText(Integer.toString(accessCount));
  }
  private JButton 
    start = new JButton("Start"),
    watcher = new JButton("Watch");
  private boolean isApplet = true;
  private int numCounters = 12;
  private int numWatchers = 15;

  class TwoCounter extends Thread {
    private boolean started = false;
    private JTextField 
      t1 = new JTextField(5),
      t2 = new JTextField(5);
    private JLabel l = 
      new JLabel("count1 == count2");
    private int count1 = 0, count2 = 0;
    public TwoCounter() {
      JPanel p = new JPanel();
      p.add(t1);
      p.add(t2);
      p.add(l);
      getContentPane().add(p);
    }    
    public void start() {
      if(!started) {
        started = true;
        super.start();
      }
    }
    public synchronized void run() {
      while (true) {
        t1.setText(Integer.toString(count1++));
        t2.setText(Integer.toString(count2++));
        try {
          sleep(500);
        } catch(InterruptedException e) {
          System.err.println("Interrupted");
        }
      }
    }
    public synchronized void synchTest() {
      incrementAccess();
      if(count1 != count2)
        l.setText("Unsynched");
    }
  }
  
  class Watcher extends Thread {
    public Watcher() { start(); }
    public void run() {
      while(true) {
        for(int i = 0; i < s.length; i++)
          s[i].synchTest();
        try {
          sleep(500);
        } catch(InterruptedException e) {
          System.err.println("Interrupted");
        }
      }
    }
  }
  class StartL implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      for(int i = 0; i < s.length; i++)
        s[i].start();
    }
  }
  class WatcherL implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      for(int i = 0; i < numWatchers; i++)
        new Watcher();
    }
  }
  public void init() {
    if(isApplet) {
      String counters = getParameter("size");
      if(counters != null)
        numCounters = Integer.parseInt(counters);
      String watchers = getParameter("watchers");
      if(watchers != null)
        numWatchers = Integer.parseInt(watchers);
    }
    s = new TwoCounter[numCounters];
    Container cp = getContentPane();
    cp.setLayout(new FlowLayout());
    for(int i = 0; i < s.length; i++)
      s[i] = new TwoCounter();
    JPanel p = new JPanel();
    start.addActionListener(new StartL());
    p.add(start);
    watcher.addActionListener(new WatcherL());
    p.add(watcher);
    p.add(new Label("Access Count"));
    p.add(aCount);
    cp.add(p);
  }
  public static void main(String[] args) {
    Sharing2 applet = new Sharing2();
    // This isn't an applet, so set the flag and
    // produce the parameter values from args:
    applet.isApplet = false;
    applet.numCounters = 
      (args.length == 0 ? 12 :
        Integer.parseInt(args[0]));
    applet.numWatchers =
      (args.length < 2 ? 15 :
        Integer.parseInt(args[1]));
    Console.run(applet, 350, 
      applet.numCounters * 50);
  }
} ///:~

You’ll notice that both run( ) and synchTest( ) are synchronized. If you synchronize only one of the methods, then the other is free to ignore the object lock and can be called with impunity. This is an important point: Every method that accesses a critical shared resource must be synchronized or it won’t work right. [ Add Comment ]

Now a new issue arises. The Watcher can never get a peek at what’s going on because the entire run( ) method has been synchronized, and since run( ) is always running for each object the lock is always tied up and synchTest( ) can never be called. You can see this because the accessCount never changes. [ Add Comment ]

What we’d like for this example is a way to isolate only part of the code inside run( ). The section of code you want to isolate this way is called a critical section and you use the synchronized keyword in a different way to set up a critical section. Java supports critical sections with the synchronized block; this time synchronized is used to specify the object whose lock is being used to synchronize the enclosed code: [ Add Comment ]

synchronized(syncObject) {
  // This code can be accessed 
  // by only one thread at a time
}

Before the synchronized block can be entered, the lock must be acquired on syncObject. If some other thread already has this lock, then the block cannot be entered until the lock is given up. [ Add Comment ]

The Sharing2 example can be modified by removing the synchronized keyword from the entire run( ) method and instead putting a synchronized block around the two critical lines. But what object should be used as the lock? The one that is already respected by synchTest( ), which is the current object (this)! So the modified run( ) looks like this:

  public void run() {
    while (true) {
      synchronized(this) {
        t1.setText(Integer.toString(count1++));
        t2.setText(Integer.toString(count2++));
      }
      try {
        sleep(500);
      } catch(InterruptedException e) {
        System.err.println("Interrupted");
      }
    }
  }

This is the only change that must be made to Sharing2.java, and you’ll see that while the two counters are never out of synch (according to when the Watcher is allowed to look at them), there is still adequate access provided to the Watcher during the execution of run( ). [ Add Comment ]

Of course, all synchronization depends on programmer diligence: every piece of code that can access a shared resource must be wrapped in an appropriate synchronized block. [ Add Comment ]

Synchronized efficiency

Since having two methods write to the same piece of data never sounds like a particularly good idea, it might seem to make sense for all methods to be automatically synchronized and eliminate the synchronized keyword altogether. (Of course, the example with a synchronized run( ) shows that this wouldn’t work either.) But it turns out that acquiring a lock is not a cheap operation—it multiplies the cost of a method call (that is, entering and exiting from the method, not executing the body of the method) by a minimum of four times, and could be much more depending on your implementation. So if you know that a particular method will not cause contention problems it is expedient to leave off the synchronized keyword. On the other hand, leaving off the synchronized keyword because you think it is a performance bottleneck, and hoping that there aren’t any collisions is an invitation to disaster. [ Add Comment ]

JavaBeans revisited

Now that you understand synchronization, you can take another look at JavaBeans. Whenever you create a Bean, you must assume that it will run in a multithreaded environment. This means that:

  1. Whenever possible, all the public methods of a Bean should be synchronized. Of course, this incurs the synchronized run-time overhead. If that’s a problem, methods that will not cause problems in critical sections can be left un-synchronized, but keep in mind that this is not always obvious. Methods that qualify tend to be small (such as getCircleSize( ) in the following example) and/or “atomic,” that is, the method call executes in such a short amount of code that the object cannot be changed during execution. Making such methods un-synchronized might not have a significant effect on the execution speed of your program. You might as well make all public methods of a Bean synchronized and remove the synchronized keyword only when you know for sure that it’s necessary and that it makes a difference. [ Add Comment ]
  2. When firing a multicast event to a bunch of listeners interested in that event, you must assume that listeners might be added or removed while moving through the list. [ Add Comment ]

The first point is fairly easy to deal with, but the second point requires a little more thought. Consider the BangBean.java example presented in the last chapter. That ducked out of the multithreading question by ignoring the synchronized keyword (which hadn’t been introduced yet) and making the event unicast. Here’s that example modified to work in a multithreaded environment and to use multicasting for events:

//: c14:BangBean2.java
// You should write your Beans this way so they 
// can run in a multithreaded environment.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.io.*;
import com.bruceeckel.swing.*;

public class BangBean2 extends JPanel 
    implements Serializable {
  private int xm, ym;
  private int cSize = 20; // Circle size
  private String text = "Bang!";
  private int fontSize = 48;
  private Color tColor = Color.red;
  private ArrayList actionListeners = 
    new ArrayList();
  public BangBean2() {
    addMouseListener(new ML());
    addMouseMotionListener(new MM());
  }
  public synchronized int getCircleSize() { 
    return cSize; 
  }
  public synchronized void 
  setCircleSize(int newSize) {
    cSize = newSize;
  }
  public synchronized String getBangText() { 
    return text; 
  }
  public synchronized void 
  setBangText(String newText) {
    text = newText;
  }
  public synchronized int getFontSize() { 
    return fontSize; 
  }
  public synchronized void 
  setFontSize(int newSize) {
    fontSize = newSize;
  }
  public synchronized Color getTextColor() {
    return tColor; 
  }
  public synchronized void 
  setTextColor(Color newColor) {
    tColor = newColor;
  }
  public void paintComponent(Graphics g) {
    super.paintComponent(g);
    g.setColor(Color.black);
    g.drawOval(xm - cSize/2, ym - cSize/2, 
      cSize, cSize);
  }
  // This is a multicast listener, which is
  // more typically used than the unicast
  // approach taken in BangBean.java:
  public synchronized void 
    addActionListener(ActionListener l) {
    actionListeners.add(l);
  }
  public synchronized void 
    removeActionListener(ActionListener l) {
    actionListeners.remove(l);
  }
  // Notice this isn't synchronized:
  public void notifyListeners() {
    ActionEvent a =
      new ActionEvent(BangBean2.this,
        ActionEvent.ACTION_PERFORMED, null);
    ArrayList lv = null;
    // Make a shallow copy of the List in case 
    // someone adds a listener while we're 
    // calling listeners:
    synchronized(this) {
      lv = (ArrayList)actionListeners.clone();
    }
    // Call all the listener methods:
    for(int i = 0; i < lv.size(); i++)
      ((ActionListener)lv.get(i))
        .actionPerformed(a);
  }
  class ML extends MouseAdapter {
    public void mousePressed(MouseEvent e) {
      Graphics g = getGraphics();
      g.setColor(tColor);
      g.setFont(
        new Font(
          "TimesRoman", Font.BOLD, fontSize));
      int width = 
        g.getFontMetrics().stringWidth(text);
      g.drawString(text, 
        (getSize().width - width) /2,
        getSize().height/2);
      g.dispose();
      notifyListeners();
    }
  }
  class MM extends MouseMotionAdapter {
    public void mouseMoved(MouseEvent e) {
      xm = e.getX();
      ym = e.getY();
      repaint();
    }
  }
  public static void main(String[] args) {
    BangBean2 bb = new BangBean2();
    bb.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e){
        System.out.println("ActionEvent" + e);
      }
    });
    bb.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e){
        System.out.println("BangBean2 action");
      }
    });
    bb.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e){
        System.out.println("More action");
      }
    });
    Console.run(bb, 300, 300);
  }
} ///:~

Adding synchronized to the methods is an easy change. However, notice in addActionListener( ) and removeActionListener( ) that the ActionListeners are now added to and removed from an ArrayList, so you can have as many as you want. [ Add Comment ]

You can see that the method notifyListeners( ) is not synchronized. It can be called from more than one thread at a time. It’s also possible for addActionListener( ) or removeActionListener( ) to be called in the middle of a call to notifyListeners( ), which is a problem since it traverses the ArrayList actionListeners. To alleviate the problem, the ArrayList is cloned inside a synchronized clause and the clone is traversed (see Appendix A for details of cloning). This way the original ArrayList can be manipulated without impact on notifyListeners( ). [ Add Comment ]

The paintComponent( ) method is also not synchronized. Deciding whether to synchronize overridden methods is not as clear as when you’re just adding your own methods. In this example it turns out that paint( ) seems to work OK whether it’s synchronized or not. But the issues you must consider are:

  1. Does the method modify the state of “critical” variables within the object? To discover whether the variables are “critical” you must determine whether they will be read or set by other threads in the program. (In this case, the reading or setting is virtually always accomplished via synchronized methods, so you can just examine those.) In the case of paint( ), no modification takes place. [ Add Comment ]
  2. Does the method depend on the state of these “critical” variables? If a synchronized method modifies a variable that your method uses, then you might very well want to make your method synchronized as well. Based on this, you might observe that cSize is changed by synchronized methods and therefore paint( ) should be synchronized. Here, however, you can ask “What’s the worst thing that will happen if cSize is changed during a paint( )?” When you see that it’s nothing too bad, and a transient effect at that, you can decide to leave paint( ) un-synchronized to prevent the extra overhead from the synchronized method call. [ Add Comment ]
  3. A third clue is to notice whether the base-class version of paint( ) is synchronized, which it isn’t. This isn’t an airtight argument, just a clue. In this case, for example, a field that is changed via synchronized methods (that is cSize) has been mixed into the paint( ) formula and might have changed the situation. Notice, however, that synchronized doesn’t inherit—that is, if a method is synchronized in the base class then it is not automatically synchronized in the derived class overridden version. [ Add Comment ]

The test code in TestBangBean2 has been modified from that in the previous chapter to demonstrate the multicast ability of BangBean2 by adding extra listeners. [ Add Comment ]

Blocking

A thread can be in any one of four states:

  1. New: The thread object has been created but it hasn’t been started yet so it cannot run. [ Add Comment ]
  2. Runnable: This means that a thread can be run when the time-slicing mechanism has CPU cycles available for the thread. Thus, the thread might or might not be running, but there’s nothing to prevent it from being run if the scheduler can arrange it; it’s not dead or blocked. [ Add Comment ]
  3. Dead: The normal way for a thread to die is by returning from its run( ) method. You can also call stop( ), but this throws an exception that’s a subclass of Error (which means you aren’t forced to put the call in a try block). Remember that throwing an exception should be a special event and not part of normal program execution; thus the use of stop( ) is deprecated in Java 2. There’s also a destroy( ) method (which has never been implemented) that you should never call if you can avoid it since it’s drastic and doesn’t release object locks. [ Add Comment ]
  4. Blocked: The thread could be run but there’s something that prevents it. While a thread is in the blocked state the scheduler will simply skip over it and not give it any CPU time. Until a thread reenters the runnable state it won’t perform any operations. [ Add Comment ]

Becoming blocked

The blocked state is the most interesting one, and is worth further examination. A thread can become blocked for five reasons: Add Comment ]

  1. You’ve put the thread to sleep by calling sleep(milliseconds), in which case it will not be run for the specified time. [ Add Comment ]
  2. You’ve suspended the execution of the thread with suspend( ). It will not become runnable again until the thread gets the resume( ) message (these are deprecated in Java 2, and will be examined further). [ Add Comment ]
  3. You’ve suspended the execution of the thread with wait( ). It will not become runnable again until the thread gets the notify( ) or notifyAll( ) message. (Yes, this looks just like number 2, but there’s a distinct difference that will be revealed.) [ Add Comment ]
  4. The thread is waiting for some I/O to complete. [ Add Comment ]
  5. The thread is trying to call a synchronized method on another object, and that object’s lock is not available. [ Add Comment ]

You can also call yield( ) (a method of the Thread class) to voluntarily give up the CPU so that other threads can run. However, the same thing happens if the scheduler decides that your thread has had enough time and jumps to another thread. That is, nothing prevents the scheduler from moving your thread and giving time to some other thread. When a thread is blocked, there’s some reason that it cannot continue running. [ Add Comment ]

The following example shows all five ways of becoming blocked. It all exists in a single file called Blocking.java, but it will be examined here in discrete pieces. (You’ll notice the “Continued” and “Continuing” tags that allow the code extraction tool to piece everything together.) [ Add Comment ]

Because this example demonstrates some deprecated methods, you will get deprecation messages when it is compiled. [ Add Comment ]

First, the basic framework:

//: c14:Blocking.java
// Demonstrates the various ways a thread
// can be blocked.
// <applet code=Blocking width=350 height=550>
// </applet>
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import com.bruceeckel.swing.*;

//////////// The basic framework ///////////
class Blockable extends Thread {
  private Peeker peeker;
  protected JTextField state = new JTextField(30);
  protected int i;
  public Blockable(Container c) {
    c.add(state);
    peeker = new Peeker(this, c);
  }
  public synchronized int read() { return i; }
  protected synchronized void update() {
    state.setText(getClass().getName()
      + " state: i = " + i);
  }
  public void stopPeeker() { 
    // peeker.stop(); Deprecated in Java 1.2
    peeker.terminate(); // The preferred approach
  }
}

class Peeker extends Thread {
  private Blockable b;
  private int session;
  private JTextField status = new JTextField(30);
  private boolean stop = false;
  public Peeker(Blockable b, Container c) {
    c.add(status);
    this.b = b;
    start();
  }
  public void terminate() { stop = true; }
  public void run() {
    while (!stop) {
      status.setText(b.getClass().getName()
        + " Peeker " + (++session)
        + "; value = " + b.read());
       try {
        sleep(100);
      } catch(InterruptedException e) {
        System.err.println("Interrupted");
      }
    }
  }
} ///:Continued

The Blockable class is meant to be a base class for all the classes in this example that demonstrate blocking. A Blockable object contains a JTextField called state that is used to display information about the object. The method that displays this information is update( ). You can see it uses getClass( ).getName( ) to produce the name of the class instead of just printing it out; this is because update( ) cannot know the exact name of the class it is called for, since it will be a class derived from Blockable. [ Add Comment ]

The indicator of change in Blockable is an int i, which will be incremented by the run( ) method of the derived class. [ Add Comment ]

There’s a thread of class Peeker that is started for each Blockable object, and the Peeker’s job is to watch its associated Blockable object to see changes in i by calling read( ) and reporting them in its status JTextField. This is important: Note that read( ) and update( ) are both synchronized, which means they require that the object lock be free. [ Add Comment ]

Sleeping

The first test in this program is with sleep( ):

///:Continuing
///////////// Blocking via sleep() ///////////
class Sleeper1 extends Blockable {
  public Sleeper1(Container c) { super(c); }
  public synchronized void run() {
    while(true) {
      i++;
      update();
       try {
        sleep(1000);
      } catch(InterruptedException e) {
        System.err.println("Interrupted");
      }
    }
  }
}
  
class Sleeper2 extends Blockable {
  public Sleeper2(Container c) { super(c); }
  public void run() {
    while(true) {
      change();
       try {
        sleep(1000);
      } catch(InterruptedException e) {
        System.err.println("Interrupted");
      }
    }
  }
  public synchronized void change() {
      i++;
      update();
  }
} ///:Continued

In Sleeper1 the entire run( ) method is synchronized. You’ll see that the Peeker associated with this object will run along merrily until you start the thread, and then the Peeker stops cold. This is one form of blocking: since Sleeper1.run( ) is synchronized, and once the thread starts it’s always inside run( ), the method never gives up the object lock and the Peeker is blocked. [ Add Comment ]

Sleeper2 provides a solution by making run( ) un-synchronized. Only the change( ) method is synchronized, which means that while run( ) is in sleep( ), the Peeker can access the synchronized method it needs, namely read( ). Here you’ll see that the Peeker continues running when you start the Sleeper2 thread. [ Add Comment ]

Suspending and resuming

The next part of the example introduces the concept of suspension. The Thread class has a method suspend( ) to temporarily stop the thread and resume( ) that restarts it at the point it was halted. resume( ) must be called by some thread outside the suspended one, and in this case there’s a separate class called Resumer that does just that. Each of the classes demonstrating suspend/resume has an associated resumer:

///:Continuing
/////////// Blocking via suspend() ///////////
class SuspendResume extends Blockable {
  public SuspendResume(Container c) {
    super(c);    
    new Resumer(this); 
  }
}

class SuspendResume1 extends SuspendResume {
  public SuspendResume1(Container c) { super(c);}
  public synchronized void run() {
    while(true) {
      i++;
      update();
      suspend(); // Deprecated in Java 1.2
    }
  }
}

class SuspendResume2 extends SuspendResume {
  public SuspendResume2(Container c) { super(c);}
  public void run() {
    while(true) {
      change();
      suspend(); // Deprecated in Java 1.2
    }
  }
  public synchronized void change() {
      i++;
      update();
  }
}

class Resumer extends Thread {
  private SuspendResume sr;
  public Resumer(SuspendResume sr) {
    this.sr = sr;
    start();
  }
  public void run() {
    while(true) {
       try {
        sleep(1000);
      } catch(InterruptedException e) {
        System.err.println("Interrupted");
      }
      sr.resume(); // Deprecated in Java 1.2
    }
  }
} ///:Continued

SuspendResume1 also has a synchronized run( ) method. Again, when you start this thread you’ll see that its associated Peeker gets blocked waiting for the lock to become available, which never happens. This is fixed as before in SuspendResume2, which does not synchronize the entire run( ) method but instead uses a separate synchronized change( ) method. [ Add Comment ]

You should be aware that Java 2 deprecates the use of suspend( ) and resume( ), because suspend( ) holds the object’s lock and is thus deadlock-prone. That is, you can easily get a number of locked objects waiting on each other, and this will cause your program to freeze. Although you might see them used in older programs you should not use suspend( ) and resume( ). The proper solution is described later in this chapter. [ Add Comment ]

Wait and notify

In the first two examples, it’s important to understand that both sleep( ) and suspend( ) do not release the lock as they are called. You must be aware of this when working with locks. On the other hand, the method wait( ) does release the lock when it is called, which means that other synchronized methods in the thread object could be called during a wait( ). In the following two classes, you’ll see that the run( ) method is fully synchronized in both cases, however, the Peeker still has full access to the synchronized methods during a wait( ). This is because wait( ) releases the lock on the object as it suspends the method it’s called within. [ Add Comment ]

You’ll also see that there are two forms of wait( ). The first takes an argument in milliseconds that has the same meaning as in sleep( ): pause for this period of time. The difference is that in wait( ), the object lock is released and you can come out of the wait( ) because of a notify( ) as well as having the clock run out. [ Add Comment ]