Swing threading and the event-dispatch thread

The evolution and pitfalls of Swing's single-threaded event model

1 2 3 4 5 Page 2
Page 2 of 5

Enter the JavaBeans component model

The Java 1.1 platform release (note that the Java Enterprise Edition didn't yet exist) introduced something called the JavaBeans paradigm. It wasn't limited to GUI development but was most prevalently used there. JavaBeans event handling didn't require you to subclass your component to add behavior; instead, you literally added implementations of interfaces to the component with methods like addActionListener(), addMouseListener(), and others.

The Listener was (and still is) a sub-interface of the java.util.EventListener interface. When a triggering event happened, the component would loop through the list of registered listeners and notify them. The listener would then respond by executing its custom business logic, without requiring you to subclass.

Java developers still are using the JavaBeans model for event handling today. To demonstrate, here's a simple program that prints a message when a button is pressed:

Listing 2. AWT button

import java.awt.*;
import java.awt.event.*;

public class HelloButton {
  public static void main(String args[]) {
    Frame frame = new Frame("Title");
    Button button = new Button("Press Here");
    ActionListener action = new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        System.out.println("Clicked");
      }
    };
    button.addActionListener(action);
    WindowListener window = new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        System.exit(0);
      }
    };
    frame.addWindowListener(window);
    frame.add(button, BorderLayout.CENTER);
    frame.setSize(200, 200);
    frame.setVisible(true);
  }
}


I should point out a couple things here. First, the button component in Listing 2 was written using the AWT (Abstract Window Toolkit) component set, because the Swing component set didn't yet exist when the JDK 1.1 first came out. Second, as you can see in the above code, the program is based on the event pattern originally described in the official Sun documentation for GUI application development. With the AWT component set, nobody cared if your code ran on the event thread or not. Instead, the GUI was created on the program's main thread.

Just for fun, Figure 1 shows the button that would result from this code.

A button component created using AWT.

Figure 1. A button component created using AWT

Swing replaces AWT

The native, peer-based component set known as AWT had difficulties with platform irregularities, causing the same application to behave differently on different desktop platforms. Instead of continuing to rely on AWT's native widget sets for each platform, the Swing component set was born, creating a purely Java based, peerless component set. This, of course, also meant learning a whole new set of tricks for GUI development. (While you can still use the AWT component set today, most developers have moved over to the Swing component set.)

What is a peer?
In AWT a peer is basically the native component specific to a given desktop platform. The Swing component set is peerless, so rather than calling a native widget, as you would with AWT, Swing gives you a blank canvas. You then paint and control the component completely from within the Java platform.

Before getting into the specifics of Swing threading, I should mention something about the timeframe of the Swing toolkit release. When Swing first became available, Java 1.1 was the primary release available. Java 1.2 was emerging but wasn't fully available yet. To manage this, Sun packaged up Swing to run with the JDK 1.1 with the help of a supplemental JAR file, as well as making it a standard part of JDK 1.2.

Dual packaging meant that the Swing component set couldn't rely on any APIs specific to Java 1.2. Sun handled this by adding some methods to a class called SwingUtilities to wrap some of the 1.2 API calls in JDK 1.1 applications. The SwingUtilities class would include the full implementations of its helper methods in Java 1.1 application, whereas Java 1.2 applications could just have SwingUtilities redirect the call to the wrapped real method.

Something funny happened along the way, though: people never stopped calling the wrapped methods. Not having to support the older code made it possible to call methods like invokeLater(), invokeAndWait(), and isEventDispatchThread() (which I'll discuss momentarily) directly on the java.awt.EventQueue object, instead of indirectly through the SwingUtilities class.

1 2 3 4 5 Page 2
Page 2 of 5