7.1 Swing Threading Restrictions
A GUI program has several
threads.
One of these threads is called the
event-dispatching
thread. This thread executes all the event-related callbacks of your
program (e.g., the actionPerformed() and
keyPressed() methods in our typing test program).
Access to all Swing objects must occur from this thread.
The reason for this is that Swing objects have complex inner state
that Swing itself does not synchronize access to. A
JSlider object, for example, has a single value
that indicates the position of the slider. If the user is in the
middle of changing the position of the slider, that value may be in
an intermediate or indeterminate state; all of that processing occurs
on the event-dispatching thread. A second thread that attempts to
read the value of the slider cannot read that value directly since by
doing so the thread may read the value while the value is in its
intermediate state. Therefore, the second thread must arrange for the
event-dispatching thread to read the value and pass the value back to
the thread.
Note that it's not enough for our second thread
simply to synchronize access to the JSlider
object. The internal Swing mechanisms aren't
synchronizing access, so the two threads still simultaneously access
the internal state of the slider. Remember that locks are
cooperative: if all threads do not attempt to acquire the lock, race
conditions can still occur.
It may seem like this restriction is overkill: the value of a
JSlider is a single variable and could simply be
made volatile. Actually, that's
not the case. The value of things within Swing components can be very
complex. Many Swing components follow a model-view-controller design
pattern, and accessing those components from one thread while the
model is being updated on the event-dispatching thread would be very
dangerous. Even the simplest of Swing components contain complex
state; it's never acceptable to call any of their
methods from a thread other than the event-dispatching thread.
Consequently, all calls to Swing objects must be made on the
event-dispatching thread. That's the thread that
Swing uses internally to change the state of its objects; as long as
you make calls to Swing objects from that thread, no
race condition can occur. Four
exceptions to this rule are:
Swing objects that have not been displayed can be created and
manipulated by any thread. That means you can create your GUI objects
in any thread but once they've been displayed, they
can be accessed only on the event-dispatching thread. A GUI object is
displayed when the show() method of its parent
frame is called. The repaint() method can be called from any
thread. The invokeLater() method can be called from any
thread. The invokeAndWait() method can be called from any
thread other than the event-dispatching thread.
|