Java threading introduction  Thread-safety  Thread methods  Interruption  Thread scheduling  Context switching  Thread priorities  sleep()  yield()  Deadlock  Threading with Swing  invokeLater()  Thread pools  CoundDownLatch  ThreadPoolExecutor  CyclicBarrier

Threads Database Profiling Regular expressions Random numbers Compression Exceptions C Equivalents in Java

Threading with Swing (ctd):
SwingUtilities.invokeLater()

In our introduction to threading with Swing, we said that any updates to the user interface must happen on the event dispatch thread. So from any other thread— in practice, that means code that isn't called directly from an event handler— we must specifically arrange for our GUI update code, and generally only that code, to be called on the event dispatch thread.

So, supposing we have a button that launches a series of database queries. We dutifully start up a new thread so that our queries won't block the user interface:

JButton b = new JButton("Run query");
b.addActionListener(new ActionListener() {
  public void actionPerformed(ActionEvent e) {
    Thread queryThread = new Thread() {
      public void run() {
        runQueries();
      }
    };
    queryThread.start();
  }
});

That was the easy bit. But now, from our query thread, we want to update a progress bar or some other component showing the current progress to the user. How can we do this if we're no longer in the event dispatch thread? Well, the SwingUtilities class, which provides various useful little calls, includes a method called invokeLater(). This method allows us to post a "job" to Swing, which it will then run on the event dispatch thread at its next convenience. So here is how to use SwingUtilities.invokeLater() from out runQueries method:

// Called from non-UI thread
private void runQueries() {
  for (int i = 0; i < noQueries; i++) {
    runDatabaseQuery(i);
    updateProgress(i);
  }
}

private void updateProgress(final int queryNo) {
  SwingUtilities.invokeLater(new Runnable() {
    public void run() {
      // Here, we can safely update the GUI
      // because we'll be called from the
      // event dispatch thread
      statusLabel.setText("Query: " + queryNo);
    }
  });
}

Here, statusLabel would be a JLabel or JTextField or something of that ilk— it doesn't matter terribly much. The point is: whatever GUI component it is, we must make sure that the code to update it is inside a call to invokeLater().

There's a bit of awkward syntax that we've glossed over, but which it's important to get used to for Swing programming generally. Essentially, we use an anonumous inner class to define our "job"— more specifically, an implementation of the Runnable interface. Anonymous inner classes are a bit of syntactic shortcut. We could also have written something like:

class UpdateJob implements Runnable {
  private final String progress;
  UpdateJob(String progress) {
    this.progress = progress;
  }
  public void run() {
    statusLabel.setText(progress);
  }
}
...
Runnable task = new UpdateJob("Query: " + i);
SwingUtilities.invokeLater(task);

But usually, it's a bit tedious to have to write a separate class definition for every pattern of update job. (Note that either way, they still compile to a different class.)

Application startup code

There's one place where it's very easy to forget that we need SwingUtilities.invokeLater(), and that's on application startup. Our applications main() method will always be called by a special "main" thread that the VM starts up for us. And this main thread is not the event dispatch thread! So:

The code that initialises our GUI must also take place in an invokeLater().

So our initial main() method should look something like this:

public class MyApplication extends JFrame {

  public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        MyApplication app = new MyApplication();
        app.setVisible(true);
      }
    });
  }

  private MyApplication() {
    // create UI here: add buttons, actions etc
  }
}
comments powered by Disqus

 Java threading articles  Java threading and concurrency  Java profiling  Java performance graph index

Unless otherwise stated, the Java programming articles and tutorials on this site are written by Neil Coffey. Suggestions are always welcome if you wish to suggest topics for Java tutorials or programming articles, or if you simply have a programming question that you would like to see answered on this site. Most topics will be considered. But in particular, the site aims to provide tutorials and information on topics that aren't well covered elsewhere, or on Java performance information that is poorly described or understood. Suggestions may be made via the Javamex blog (see the site's front page for details).
Copyright © Javamex UK 2013. All rights reserved.