Using the SwingWorker Class (version 3)

edit

Note: The implementation of the SwingWorker class has been updated twice, most recently in February 2000. The first update (in January 1999) allowed programs to safely interrupt the worker thread. The most recent update (called "SwingWorker 3") was to fix a subtle threading bug that could cause a NullPointerException.

The SwingWorker class is implemented in SwingWorker.java, which is not in the Swing release. To use the SwingWorker class, you first create a subclass of it. The subclass must implement the construct method so that it contains the code to perform your lengthy operation. When you instantiate your SwingWorker subclass, the SwingWorker creates a thread but does not (as of SwingWorker 3) start it. You then invoke start on your SwingWorker object to start the thread, which then calls your construct method. Here is an example of using a SwingWorker to move a time-consuming task from an action event listener into a background thread, so that the GUI remains responsive. //OLD CODE: public void actionPerformed(ActionEvent e) {

   ...
   //...code that might take a while to execute is here...
   ...

}

//BETTER CODE: public void actionPerformed(ActionEvent e) {

   ...
   final SwingWorker worker = new SwingWorker() {
       public Object construct() {
           //...code that might take a while to execute is here...
           return someValue;
       }
   };
   worker.start();  //required for SwingWorker 3
   ...

} The value that construct returns can be any object. If you need to get the value, you can do so by invoking the get method on your SwingWorker object. Be careful about using get. Because it blocks, it can cause deadlock. If necessary, you can interrupt the thread (causing get to return) by invoking interrupt on the SwingWorker. If you need to update the GUI when the time-consuming operation completes, you can do so either by using get (which is dangerous, as we noted) or by overriding the finished method in your SwingWorker subclass. The finished method runs after the construct method returns. Because the finished method executes in the event-dispatching thread, you can safely use it to update Swing components. Of course, you shouldn't put time-consuming operations in your finished implementation. The following example of implementing finished is taken from IconDemoApplet.java . For a full discussion of this applet, including how it improves perceived performance by using background threads to load images, see How to Use Icons. public void actionPerformed(ActionEvent e) {

   ...
   if (icon == null) {     //haven't viewed this photo before
       loadImage(imagedir + pic.filename, current);
   } else {
       updatePhotograph(current, pic);
   }

} ... //Load an image in a separate thread. private void loadImage(final String imagePath, final int index) {

   final SwingWorker worker = new SwingWorker() {
       ImageIcon icon = null;
       public Object construct() {
           icon = new ImageIcon(getURL(imagePath));
           return icon; //return value not used by this program
       }
       //Runs on the event-dispatching thread.
       public void finished() {
           Photo pic = (Photo)pictures.elementAt(index);
           pic.setIcon(icon);
           if (index == current)
               updatePhotograph(index, pic);
       }
   };
   worker.start(); 

}

Specific Issues Addressed by Other Implementations

edit

One of the more predominate use cases that occurs over and over is the case where multiple components data needs to be updated and you have multiple bits to manage where components need to be disabled or have their state changed in various ways.

In many Java GUI applications, there can be downloaded code where part of the GUI might come from a remote codebase etc.

In the SwingUtil project on java.net, at http://swingutil.dev.java.net, there is a SyncThread class that encompasses a number of additional issues. It uses Generics to manage types, and it tries to completely deal with all kinds of issues. It manages the context class loader so that the EDT is run with the context class loader set to the class loader of the class that the SwingWorker was created with. It uses the same JAAS Subject that the creating thread was running with as well, inside of the EDT (when Subject is set).

It provides the ability to create sequences of events and run those sequences to completion so that if multiple components have data being filled from different sources, you don't have to return an array or other plastic container from construct() so that you have all the data.

Further, it accepts a list of Component and/or Action values in the constructor which are disabled while all of the work is done, and then re-enabled when the work completes.

Hopefully, someday context ClassLoaders and JAAS Subject will become true, first class citizens in the JVM, instead of after thoughts that are still largely ignored by infrastructure. —Preceding unsigned comment added by Greggwon (talkcontribs) 19:40, 15 September 2009 (UTC)Reply

Backport of Java 6 SwingWorker

edit

A backport of the Java 6 SwingWorker has been available at https://swingworker.dev.java.net/ since March 2007. Apart from the package name, it is compatible with the Java 6 SwingWorker.

Perhaps less prominence can be given to Version 3, now that there is a compatible alternative?