Threads and Swing

If your program creates and refers to its GUI the correct way, you might not need to worry about threads. [1] If your program is an applet, it's safe to construct its GUI in the init method. You're also safe if your program is an application with the following common pattern:

[1] For general information on threads, see Chapter 8, Threads: Doing Two or More Tasks at Once (page 269).

//Thread-safe example public class MyApplication { public static void main(String[] args) { JFrame f = new JFrame(...); ...//Add components to the frame here... f.pack(); f.setVisible(true); //Don't do any more GUI work here. } ... //All manipulation of the GUI -- setText, getText, etc. //is performed in event handlers such as actionPerformed(). ... }

However, if your program creates threads to perform tasks that affect the GUI or if it manipulates an already visible GUI in response to anything but a standard event, read on.

The Single-Thread Rule

Swing components can be accessed by only one thread at a time, generally the event-dispatching thread. Thus, the single-thread rule is as follows.

Rule

Once a Swing component has been realized, all code that might affect or depend on the state of that component should be executed in the event-dispatching thread.

This rule might sound scary, but for many simple programs, you don't have to worry about threads.

Before we go into detail about how to write Swing code, let's define the term realized. Realized means that the component has been painted on-screen or that it is ready to be painted. A Swing component that's a top-level window is realized by having one of these methods invoked on it: setVisible(true), show, or pack. Once a window is realized, all the compo-nents it contains are realized. Another way to realize a component is to add it to a container that's already realized. You'll see examples of realizing components later.

Note

The show method does the same thing as setVisible(true).

 

Exceptions to the Rule

The rule that all code that might affect a realized Swing component must run in the event-dispatching thread has a few exceptions.

A few methods are thread safe.

In the Swing API documentation, thread-safe methods are marked with this text:

This method is thread safe, although most Swing methods are not.

An application's GUI can often be constructed and shown in the main thread.

As long as no Swing or other components have been realized in the current runtime environment, it's fine to construct and show a GUI in the main thread of an application. To help you see why, here's an analysis of the thread safety of the thread-safe example. To refresh your memory, here are the important lines from the example:

public static void main(String[] args) { JFrame f = new JFrame(...); ...//Add components to the frame here... f.pack(); f.setVisible(true); //Don't do any more GUI work here. }

  1. The example constructs the GUI in the main thread. In general, you can construct (but not show) a GUI in any thread, as long as you don't make any calls that refer to or affect already realized components.
  2. The components in the GUI are realized by the pack call.
  3. Immediately afterward, the components in the GUI are shown with the setVisible (or show) call. Technically the setVisible call is unsafe, because the components have already been realized by the pack call. However, because the program doesn't already have a visible GUI, it's exceedingly unlikely that a paint request will occur before setVisible returns.
  4. The main thread executes no GUI code after the setVisible call. This means that all GUI work moves from the main thread to the event-dispatching thread, and the example is, in practice, thread safe.

An applet's GUI can be constructed and shown in the init method.

Existing browsers don't paint an applet until after its init and start methods have been called. Thus constructing the GUI in the applet's init method is safe, as long as you never call show() or setVisible(true) on the applet object.

These JComponent methods are safe to call from any thread: repaint and revalidate .

These methods queue requests to be executed on the event-dispatching thread.

Listener lists can be modified from any thread.

It's always safe to call the addListenerType Listener and removeListenerType Listener methods. The add/remove operations have no effect on an event dispatch that's under way.

How to Execute Code in the Event-Dispatching Thread

Most postinitialization GUI work naturally occurs in the event-dispatching thread. Once the GUI is visible, most programs are driven by events, such as button actions or mouse clicks, which are always handled in the event-dispatching thread.

However, some programs need to perform nonevent-driven GUI work after the GUI is visible. Here are two examples.

Programs that must perform a lengthy initialization operation before they can be used

This kind of program should generally show some GUI while the initialization is occurring and then update or change the GUI. The initialization should not occur in the event-dispatching thread; otherwise, repainting and event dispatching would stop. However, after initialization, the GUI update or change should occur in the event-dispatching thread, for thread-safety reasons.

Programs whose GUI must be updated as the result of nonstandard events

For example, suppose that a server program can get requests from other programs that might be running on different machines. These requests can come at any time, and they result in one of the server's methods being invoked in a possibly unknown thread. How can that method update the GUI? By executing the GUI-update code in the event-dispatching thread.

The SwingUtilities [1] class provides two methods to help you run code in the event-dispatching thread:

[1] API documentation for this class is available on the CD that accompanies this book and online at: http://java.sun.com/products/jdk/1.2/docs/api/javax/swing/SwingUtilities.html

invokeLater

Requests that some code be executed in the event-dispatching thread. This method returns immediately, without waiting for the code to execute.

invokeAndWait

Acts like invokeLater, except that this method waits for the code to execute. As a rule, you should use invokeLater rather than this method.

For more information on deploying threads in your Swing programs, see the section "How to Use Threads" in the book The JFC Swing Tutorial. This section is also available on this book's CD and online at:

http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html

Категории