Threading with Swing

You may have written a GUI-enabled application using a framework such as Swing, and never even given a thought to threads. And for some types of application, you pretty much don't have to. If everything in your application happens directly in response to a button click or other Swing event, and your application never "does things with threads" (it never sleeps, spawns another thread or process, "does something in the background" etc), then be it by good design or good fortune, it may be behaving correctly. But there are times, particularly if your application does want to "do something with threads", when you need to understand how threading works with respect to the GUI system.

(追記) (追記ここまで)

As you'll know if you've programmed with GUI systems such as Swing, everything generally happens in response to events. You define an event handler, which is effectively the code you would like to be called when something happens. For example, we can define a button like this:

JButton b = new JButton("Click me");
b.addActionListener(new ActionListener() {
 public void actionPerformed(ActionEvent e) {
 // Code will be performed when button clicked
 }
});

To our program, the call to our method just "comes out of nowhere". But in reality, it must come from somewhere. That is: there must be some particular thread that's calling into our method. Well, there is, and it's quite a well-defined thread.

The event dispatch thread

The thread making calls to our event handlers is the event dispatch thread. This is a special thread that the GUI system sets up for performing UI tasks. Essentially, all user interface code will be executed by this special thread. Having a single designated thread handling the entire UI avoids a lot of issues that would occur if we tried to allow, say, different event handlers to be called by arbitrary threads.

In most Swing applications, if you've not thought about it and done anything special to use other threads, then practically all of your application will probably happen in the event dispatch thread. What you might not have thought about is whether it's all happening correctly...

Proper threading behaviour of GUI applications

There are essentially two rules of thumb that you need to remember:

  • always manipulate your user interface from the event dispatch thread (with one or two safe exceptions);
  • never block or delay the event dispatch thread— in other words, never call methods such as Thread.sleep(), Object.wait(), Condition.await() inside an event handler.

In more detail, these two guidelines have a few implications:

  • all tasks that we perform inside an event handler should be instantaneous; we should not perform a long-running task (such as making a database query) or call Thread.sleep() or Object.wait() or similar calls directly from an event handler;
  • to perform such long-running tasks, we need to arrnage for them to happen in another thread, e.g. by starting a new thread specially for the task;
  • we need to be wary of the more "subtle" library calls that might cause our thread to wait: if we use one of the concurrency utilities such as a ThreadPoolExecutor, we need to make sure we use a variant that won't ever block waiting for room in the queue; other slightly more obvious no-nos are awaiting a latch, joining another thread, calling Future.get()... essentially anything that "waits" for something cannot be called inside an event handler;
  • if we're in our other thread and need to update the UI (e.g. to report progress to the user), we generally need to arrange for that update code— and only the update code— to happen in the event dispatch thread;
  • by "manipulating the UI", we mean calling methods on or changing the state of any Swing components but also modifying any objects they depend on such as table models, cell renderers etc; firing events must also happen in the event dispatch thread.

How do you make something happen in the event dispatch thread?

So far, we've glibly said that in certain cases we must run something on the event dispatch thread. But how do we actually do that? On the next page, we look at the special method SwingUtilities.invokeLater() which provides us with this functionality.


If you enjoy this Java programming article, please share with friends and colleagues. Follow the author on Twitter for the latest news and rants. Follow @BitterCoffey

Editorial page content written by Neil Coffey. Copyright © Javamex UK 2021. All rights reserved.

AltStyle によって変換されたページ (->オリジナル) /