Java Solaris Communities My SDN Account Join SDN
 
Core Java Technologies Tech Tips

Multithreading in Swing and ThreadLocal Variables for Storing Thread-Specific State Information

In This Issue

Welcome to the Core Java Technologies Tech Tips for December 8, 2003. Here you'll get tips on using core Java technologies and APIs, such as those in Java 2 Platform, Standard Edition (J2SE).

This issue covers:

-Multithreading in Swing
-ThreadLocal Variables for Storing Thread-Specific State Information

These tips were developed using Java 2 SDK, Standard Edition, v 1.4.

This issue of the Core Java Technologies Tech Tips is written by John Zukowski, president of JZ Ventures, Inc.

See the Subscribe/Unsubscribe note at the end of this newsletter to subscribe to Tech Tips that focus on technologies and products in other Java platforms.

Multithreading in Swing

The Swing component set was first introduced in 1996, to be used in conjunction with the 1.1 version of what was then known as the Java Development Kit (JDK). The Swing component set provided (and still provides) an alternative to the Abstract Window Toolkit (AWT) component set for developing graphical user interfaces. AWT relied on a platform's native widget set for the lowest common denominator for cross-platform user interfaces. The Swing component set, as part of the Java Foundation Classes (JFC), introduced a pure Java technology-based solution, where all the drawing code lived within the Java platform.

In nearly every tutorial on the Swing component set, the component set has been described as single threaded, that is, all accesses to a realized component must be done from the event dispatch thread. The term "realized" essentially means displayed on the screen. In practice, this means that prior to showing a Swing component on the screen, you can build up a screen and get and set the necessary properties. This is demonstrated in the following program, Swing1, which adds a button to a frame and then shows the frame:

   import javax.swing.*;
   import java.awt.*;

   public class Swing1 {
     public static void main(String args[]) {
       JFrame frame = new JFrame();
       frame.setTitle("Title");
       frame.setDefaultCloseOperation(
         JFrame.EXIT_ON_CLOSE);
       JButton button = new JButton();
       button.setText("Hello, World!");
       frame.getContentPane().add(button,
         BorderLayout.CENTER);
       frame.setSize(200, 100);
       frame.show();
      }
   }
 

Looking at this simple program, you might assume that there's nothing wrong with it. Similar programs are in practically every tutorial and article on Swing, including those in the Core Java Technologies Tech Tips. Simple doesn't make something right though. In fact, there is something wrong with the program.

The culprit here is the show method call. More precisely, the culprit is the underlying call to setVisible(true) which triggers a call to pack the container. Both setVisible and pack will create the associated peer for the frame. With the creation of the peer, the system creates the event dispatch thread. This makes things problematic because the event dispatch thread could be notifying listeners while pack and validate are still processing. This situation could result in two threads going through the Swing component-based GUI -- it's a serious flaw that could result in deadlocks or other related threading issues. A pack call causes components to be realized. As they are being realized (that is, not necessarily visible), they could trigger listener notification on the event dispatch thread.

How do you fix the problem? Simply don't show a frame on the main thread. You can still do all the GUI creation code there. However, when it's time to make the window visible, do it on the event dispatch thread. This ensures that, at most, only one thread will be initializing the Swing components.

Note: Recommendations for thread safety have changed slightly since this article was written. It is now recommended that you use invokeLater to create the GUI on the event-dispatching thread, rather than constructing the GUI on the main thread. See The Java Tutorial sections Initial Threads for a template you can use and How to Use Threads for further details.

Here's the original sample program reworked to be thread safe.

   import javax.swing.*;
   import java.awt.*;

   public class Swing2 {
      private static class FrameShower 
                                  implements Runnable {
        final Frame frame;
        public FrameShower(Frame frame) {
          this.frame = frame;
        }
        public void run() {
          frame.show();
        }
      }
      public static void main(String args[]) {
        JFrame frame = new JFrame();
        frame.setTitle("Title");
        frame.setDefaultCloseOperation(
          JFrame.EXIT_ON_CLOSE);
        JButton button = new JButton();
        button.setText("Hello, World!");
        frame.getContentPane().add(button,
          BorderLayout.CENTER);
        frame.setSize(200, 100);
        Runnable runner = new FrameShower(frame);
        EventQueue.invokeLater(runner);
      }
   }
 

Compared to the original example, the only code changes are to create a Runnable class:

   private static class FrameShower 
                               implements Runnable {
     final Frame frame;
     public FrameShower(Frame frame) {
       this.frame = frame;
     }
     public void run() {
       frame.show();
     }
   }
     ...
     Runnable runner = new FrameShower(frame);
 

And then pass that Runnable object to the invokeLater (or invokeAndWait) method:

   EventQueue.invokeLater(runner);
 

Called correctly, this results in a truly thread-safe version of the sample program. You might consider examining your programs and updating them if they improperly dealt with threading in Swing.

For more information about threads and Swing, see the Threads and Swing trail in the Java Tutorial.

ThreadLocal Variables for Storing Thread-Specific State Information

Have you ever needed variables that were local to the scope of a thread, where each thread managed its storage, and it would be impossible for one thread to access the state information of another thread? The standard libraries offer two classes that provide this capability: ThreadLocal and InheritableThreadLocal.

Let's look at a simple use of the classes.

  import java.util.Random;

  public class ThreadLocal1 {

    // Define/create thread local variable
    static ThreadLocal threadLocal = 
                                   new ThreadLocal();
    // Create class variable
    static volatile int counter = 0;
    // For random number generation
    static Random random = new Random();

    // Displays thread local variable, counter, 
    // and thread name
    private static void displayValues() {
      System.out.println (
        threadLocal.get() + "\t" + counter +
        "\t" + Thread.currentThread().getName());
    }

    public static void main (String args[]) {

      // Each thread increments counter
      // Displays variable info
      // And sleeps for the random amount of time
      // Before displaying info again
      Runnable runner = new Runnable() {
        public void run() {
          synchronized(ThreadLocal1.class) {
            counter++;
          }
          threadLocal.set(
             new Integer(random.nextInt(1000)));
          displayValues();
          try {
            Thread.sleep (
              ((Integer)threadLocal.get()).intValue());
            displayValues();
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
        }
      };

      // Increment counter, access thread local from 
      // a different thread, and display the values
      synchronized(ThreadLocal1.class) {
          counter++;
      }
      threadLocal.set(
         new Integer(random.nextInt(1000)));
      displayValues();

      // Here's where the other threads
      //  are actually created
      for (int i=0; i<5; i++) {
        Thread t = new Thread(runner);
        t.start();
      }
    }
  }
 

The ThreadLocal1 class has two static variables: counter, which is a common integer primitive, and threadLocal, which is the ThreadLocal variable. Typically, with class variables, the same value is shared by all instances of the class. With ThreadLocal, that is not the case. Instead, each usage of the ThreadLocal class within the same thread shares the same static information. Usages of the ThreadLocal class within different threads result in different static information.

In the ThreadLocal1 example, the ThreadLocal instance is initialized with a random number between 0 and 999.

   threadLocal.set(
     new Integer(random.nextInt(1000)));
 

A number of different threads are created. For each thread, the state information for the two class variables are displayed. The thread then sleeps for an amount of time in milliseconds specified by the random number in the ThreadLocal. After that, the state information for the two class variables are redisplayed. If you run ThreadLocal1, you should see output that looks something like this:

   828     1       main
   371     2       Thread-0
   744     3       Thread-1
   734     4       Thread-2
   189     5       Thread-3
   790     6       Thread-4
   189     6       Thread-3
   371     6       Thread-0
   734     6       Thread-2
   744     6       Thread-1
   790     6       Thread-4
 

The point shown here is that where the thread name in column three is the same, the ThreadLocal variable in column one remains the same throughout the program's run. By comparison, the normal static variable in column two changes throughout the run of the program, and retains that new value when reexamining old threads. This is exactly what a properly synchronized static variable should do.

Each run of the program produces different output in all columns, so don't be surprised if your results show the times in column one that are different than shown above, or if the order of the names for the last five rows is different. That order is based on the times shown in the first column.

Note that thread local variables are not just another form of instance variables. If you access ten instances of a class, all within a common thread, their ThreadLocal information will be the same. However, as soon as one of those instances is accessed by a different thread, that ThreadLocal information will be different.

The ThreadLocal class contains only three methods: get, set, and initialValue. In the ThreadLocal1 example, the set method is called after creating the instance. Instead of post-initializing the state of the ThreadLocal, you could subclass ThreadLocal and override its initialValue method. The ThreadLocal2 class below does just that. The generated output should be similar to that produced by ThreadLocal1.

   import java.util.Random;

   public class ThreadLocal2 {

     // Create thread local class
     // Initial value is a random number from 0-999
     private static class MyThreadLocal
                                  extends ThreadLocal {
       Random random = new Random();
       protected Object initialValue() {
         return new Integer(random.nextInt(1000));
       }
     }

     // Define/create thread local variable
     static ThreadLocal threadLocal =
                           new MyThreadLocal();

     // Create class variable
     static volatile int counter = 0;

     // For random number generation
     static Random random = new Random();

     // Displays thread local variable, counter,
     // and thread name
     private static void displayValues() {
       System.out.println (
         threadLocal.get() + "\t" + counter +
         "\t" + Thread.currentThread().getName());
     }
    
     public static void main (String args[]) {

       // Each thread increments counter
       // Displays variable info
       // And sleeps for the random amount of time
       // Before displaying info again
       Runnable runner = new Runnable() {
         public void run() {
           synchronized(ThreadLocal2.class) {
             counter++;
           }
           displayValues();
           try {
             Thread.sleep (
               ((Integer)threadLocal.get()).intValue());
             displayValues();
           } catch (InterruptedException e) {
             e.printStackTrace();
           }
         }
       };

       // Another instance of class created
       // and values displayed
       displayValues();

       // Here's where the other threads
       // are actually created
       for (int i=0; i<5; i++) {
         Thread t = new Thread(runner);
         t.start();
       }
     }
   } 
 

The initialValue method of ThreadLocal is called on the first call to get the state by each thread. If set has already been called, the initialValue method is never invoked. When using the initialValue method, remember to make it protected, not public. That's because you typically do not want it callable by anyone at any time. When initialValue is not overridden, the initial value for the object representing the thread local variable is null.

The contents of the ThreadLocal variable can be any Object type. In ThreadLocal2, the content is an Integer. When getting the state with get, remember to cast the Object to the appropriate type.

There is a second type of ThreadLocal type called InheritableThreadLocal. Like ThreadLocal, each thread that uses an InheritableThreadLocal has its own state object. Where the two differ is that the initial value for the InheritableThreadLocal is acquired from the state of the variable from the creating thread. When that state changes, it is only changed in the local thread, not in any other threads. The new childValue method of InheritableThreadLocal is used to initialize its state. The method is called by the child's constructor, not when you try to get the state.

To examine the use of ThreadLocal in practice, explore the Charset class in java.nio.charset, or the LogRecord class in java.util.Logging. In the Charset case, a ThreadLocal is used to look up character set encoders and decoders. It serves as a gatekeeper to prevent some initialization code from running prematurely. In LogRecord, the use of ThreadLocal ensures that each thread is assigned a unique id for logging.

Developer Assistance

Need programming advice on Java SE? Try Developer Expert Assistance.

Rate and Review
Tell us what you think of the content of this page.
Excellent   Good   Fair   Poor  
Comments:
Your email address (no reply is possible without an address):
Sun Privacy Policy

Note: We are not able to respond to all submitted comments.