|
Java threading introduction
Thread-safety
Thread methods
Interruption
Thread scheduling
Thread priorities
sleep()
yield()
Deadlock
Threading with Swing
invokeLater()
Thread pools
CoundDownLatch
ThreadPoolExecutor
CyclicBarrier
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
}
}
Did this article solve your problem? If not, you can now
post a comment or question
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 2009. All rights reserved.
|