Even if you have never used the Thread class, you
unwittingly are using Threads whenever you use Swing.
To write even the simplest Swing program you must follow some simple thread
rules to avoid trouble.
Thread Safety
Unlike the AWT, Swing is not thread-safe. Officially the AWT is not thread-safe
either. Sun does not guarantee that AWT is thread-safe. You are also supposed to
do all AWT calls from the event dispatch thread.
The EDT
The Swing EventDispatchThread thread is the thread
that prods your various listeners with events. It is sometimes called the EDT,
Event Dispatch Thread.
Sometimes it is called simply the Swing thread, even
though it handles AWT as well and even though its Thread name is AWT-EventQueue-0.
There are two fundamental things to understand about Swing and threads:
- Time-consuming tasks should not be run
on the EDT (aka Event Dispatch Thread
aka Swing thread). Otherwise the application becomes unresponsive. The EDT is
busy executing your task and hence can’t process GUI events.
- Swing components should be accessed on
the EDT (aka Event Dispatch Thread
aka Swing thread) only. To access components from other threads, you must use SwingUtilities.
invokeAndWait, SwingUtilities.
invokeLater or SwingWorker.
invokeLater and invokeAndWait
You can’t directly meddle with Swing components, or their backing data
models from a second thread. The contract is, if you want to do anything to a
Swing component that could have any effect on it’s display from an
application thread you should add it to the event dispatch thread’s queue
via SwingUtilities.invokeLater( Runnable
) or SwingUtilities.invokeAndWait( Runnable
) so that it will be done on the same thread that Swing itself uses.
Obviously you can call Swing methods directly from the EventDispatchThread.
The AWT equivalents are called java.awt.EventQueue.invokeLater(
Runnable ) and EventQueue.invokeAndWait(
Runnable ). The Swing versions are just
wrappers around the AWT methods, so you might as well just use the AWT versions
all the time. The Swing versions were stop gaps until the AWT versions were
available.
The good news is, even though, with invokeLater and invokeAndWait,
you are using the Runnable interface normally
associated with starting new threads, you don’t actually have the overhead
of creating a new Thread since you are just calling
the run method on the already existing Swing thread.
Here is how you would wrap a piece of GUI-manipulating code to run from any
thread.
SwingUtilities.invokeLater( new Runnable() {
public void run()
{
abort.setEnabled( false );
}
} );
Thread Safe Swing Methods
There are a few exceptions to the general rule of having to invoke Swing methods
from the EventDispatchThread, most notably it is safe
to call to the following methods from any thread:
Component.repaint
JEditorPane.replaceSelection
JEditorPane.setText
JTextArea.append
JTextArea.insert
JTextArea.replaceRange
JTextComponent.replaceSelection
JTextComponent.setText
JTextPane.insertComponent
JTextPane.insertIcon
JTextPane.insertLogicalStyle
JTextPane.replaceSelection
JTextPane.setCharacterAttributes
JTextPane.setParagraphAttributes
PlainDocument.setText
Most Swing methods are not safe including:
Container.invalidate
Container.revalidate
Container.validate
JButton.setText
JComponent.revalidate
JComponent.setBackground
JComponent.setEnabled
JComponent.setFont
JComponent.setForeground
JComponent.setVisible
JComponent.validate
JLabel.setText
JTextArea.setText
JTextComponent.setText
If you are unsure, check the Javadoc.
Originally you were allowed to construct new Swing objects on other threads and
call their methods, but once they were realised, —
once you had called pack/setVisible(
true ), from that point on you had manipulate the Components
only from the Swing thread (which is not the same thread as the main thread).
Sun now recommends doing all manipulation of Swing components, realised or not,
via the Swing (aka EDT) thread,
Best Practice
Sun now discourages even that practice.
Sun now recommends that for any new code, you do all
your non-event thread calls to Swing methods, even constructing a JFrame,
via SwingUtilities.invokeLater( Runnable ) or SwingUtilities.invokeAndWait(
Runnable ).
Here is the safer way to fire up a GUI with all the initialisation on the Swing
thread:
The good news is, even though you are using Runnable,
you don’t have the overhead of actually creating a new Thread
since you are just calling the run method on the
already existing Swing Thread.
Which Thread Am I On?
You are not on the Swing event thread when main
first starts up! You are on it in your event listeners. You are tell if you are
on it with:
The Sleep Error
One of the most common errors is to tie up the AWT/Swing event thread with some
long running computation or even a sleep. Everything
freezes up. The GUI can’t respond to mouse clicks and no repainting
happens. You have to spin the time-consuming task off on its own thread or use a Timer.
SwingWorker makes it easy to set up a background Thread
that interacts with the GUI. If the background task does not use the GUI widgets,
it is simpler to use an ordinary Thread instead.
If you violate these rules, the entire system starts to behave unpredicably and
irrationally. If by violating these rules, you manage to create two event-processing
threads, life gets really interesting as they unpredictably fight with each
other handling Swing events.
Learning More