Don’t Block the GUI #92
Chapter 12, Miscellany
|
463
HACK
To Block or Not to Block
The demo application is shown in Figure 12-7.
class NonBlockingLoadAction extends AbstractAction implements Runnable {
// note that this doesn't offer a means of being interrupted
// so it refuses second launch instead
public void actionPerformed (ActionEvent e) {
if (loaderThread != null)
return;
loaderThread = new Thread ((Runnable) this);
loaderThread.start( );
}
public void run( ) {
loadURL(true);
loaderThread = null;
}
}
}
Figure 12-7. Blocking and not blocking AWT event dispatch by loading a URL into a
JTextArea
Example 12-8. Demonstration of both blocking and not blocking the AWT event-dispatch
thread during lengthy actions (continued)
464
|
Chapter 12, Miscellany
#92 Don’t Block the GUI
HACK
After launching the application, try loading the same address with the block-
ing and non-blocking Load buttons. In the blocking version, you should see
that you can’t open the
JMenu
or reposition the caret in the
JTextField
. If
you’ve already filled the
JTextArea
, you’ll find that the scrollbar is unrespon-
sive while you’re blocking. Drag a window over the demo and then bring the
demo to the foreground—on some operating systems, the area previously
obscured by the window won’t repaint.
Of course, none of this happens when you use the non-blocking version.
Take a look back at Example 12-8. There are separate
Actions for the
blocking and non-blocking buttons and menu items; but in the end, both of
them call
loadURL( ). The difference is how they call it: the
BlockingLoadAction calls loadURL( ) directly in actionPerformed( ), while the
NonBlockingLoadAction creates a Thread and runs it. As an aside, both of
these methods check to see if there’s already a thread running from the
NonBlockingLoadAction, as you wouldn’t want two of these threads running
at once, since the first one would populate the text area only to have it clob-
bered when the second finished.
But back to the point: because the non-blocking load is only responsible for
creating and starting a thread, it returns almost immediately. When you use
this loading option, you should find that the GUI remains extremely respon-
sive—menus are viewable, the text field is responsive, you can drag the
scrollbar, etc.
The only thing that’s a little tricky in the threaded case is what to do when
the thread finishes. Swing is not thread-safe, so you’re not supposed to make
Swing calls from any thread other than the event-dispatch thread. If you do,
you’ll eventually create crazy bugs that look like
NullPointerExceptions or
ArrayIndexOutOfBoundsExceptions, but which are really coming from two
threads trying to work with one widget at the same time, thus setting and
resetting its variables in hard-to-debug race conditions.
Now, you might be thinking, “wasn’t getting code off of the event-dispatch
thread the whole point of this exercise?” Only to a certain extent—the strat-
egy is to put as little on event dispatch as possible, but you still need to put
any Swing calls on it. So, you put the network loading in its own thread, but
put the update to the
JTextArea back on event dispatch. In other words:
“render unto event dispatch what is Swing’s…”.
You can do your Swing work with a worker thread, which is actually just
any
Runnable, typically one whose run( ) method does some Swing work. By
calling
SwingUtilitiesinvokeAndWait( ) or invokeLater( )—the difference is

Get Swing Hacks now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.