Nothing theoretical about it. It's very practical. The SwingUtilities.invokeLater()
method guarantees that the code within the Runnable
will run on the Event Dispatch Thread (EDT)
. This is important because Swing is not thread-safe, thus anything related to the GUI (Swing
, etc.) needs to run on the EDT
. The EDT
is a "it happens whenever it happens" thread that makes no guarantees about the order in which things are executed. If the GUI code is executed within a background thread (say, within a SwingWorker
instance), then it can throw errors. I learned this the hard way: in my learning years, executing GUI-changing code within a background thread caused random, inconsistent RuntimeException
s that I couldn't figure out. It was a good learning experience (SwingWorker
has a doInBackground()
method for background tasks and a done()
method for EDT
tasks).
In the same way you don't want to execute GUI code on a background thread, you also don't want to execute large operations (database queries, etc) on the EDT
. This is because the EDT
is dispatching all of the GUI events so everything on the EDT
should be very short and sweet. You can easily see this with a JProgressBar
set to indeterminate.
This SSCCE should illustrate it nicely. Notice the motion of the JProgressBar
as method()
is called, once on a background thread and once on a EDT
thread.
import javax.swing.JFrame;
import javax.swing.JProgressBar;
import javax.swing.SwingWorker;
/**
*
* @author Ryan
*/
public class Test {
public static void main(String args[]) {
JFrame frame = new JFrame();
JProgressBar jpb = new JProgressBar();
jpb.setIndeterminate(true);
frame.add(jpb);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
new Task().execute();
}
public static void method() { // This is a method that does a time-consuming task.
for(int i = 1; i <= 5; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i);
}
}
static class Task extends SwingWorker<Void, Void> {
@Override
protected Void doInBackground() throws Exception {
/* Executing method on background thread.
* The loading bar should keep moving because, although method() is time consuming, we are on a background thread.
*/
method();
return null;
}
@Override
protected void done() {
/* Executing method on Event Dispatch Thread.
* The loading bar should stop because method() is time consuming and everything on the Event Dispatch Thread
* (like the motion of the progress bar) is waiting for it to finish.
*/
//
method();
}
}
}
Hope this helps.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…