SwingWorker not on Java 6.0

SwingWorker is useful when a time-consuming task has to be performed following a user-interaction event (for example, parsing a huge XML File, on pressing a Button). The most straightforward way to do it is :


 private Document doc;
 ...
 JButton button = new JButton("Open XML");
 button.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
       doc = loadXML();
    }
 });

This will work, but unfortunately, the loadXML() method will be called in the same thread as the main Swing thread, so if the method needs time to perform, the GUI will freeze during this time.


package com.wsjoung.demo;
import javax.swing.SwingUtilities;

public abstract class SwingWorker {
    // see getValue(), setValue()
    private Object value;
    private Thread thread;

    private static class ThreadVar {
        private Thread thread;
        ThreadVar(Thread t) { thread = t; }
        synchronized Thread get() { return thread; }
        synchronized void clear() { thread = null; }
    }

    private ThreadVar threadVar;

    protected synchronized Object getValue() {
        return value;
    }

    private synchronized void setValue(Object x) {
        value = x;
    }

    public abstract Object construct();

    public void finished() {
    }

    public void interrupt() {
        Thread t = threadVar.get();
        if (t != null) {
            t.interrupt();
        }
        threadVar.clear();
    }

    public Object get() {
        while (true) {
            Thread t = threadVar.get();
            if (t == null) {
                return getValue();
            }
            try {
                t.join();
            }
            catch (InterruptedException e) {
                // propagate
                Thread.currentThread().interrupt();
                return null;
            }
        }
    }

    public SwingWorker() {
        final Runnable doFinished = new Runnable() {
           public void run() { finished(); }
        };

        Runnable doConstruct = new Runnable() {
            public void run() {
                try {
                    setValue(construct());
                }
                finally {
                    threadVar.clear();
                }

              SwingUtilities.invokeLater(doFinished);
            }
        };

        Thread t = new Thread(doConstruct);
        threadVar = new ThreadVar(t);
        t.start();
    }
}

SwingWorker.java


public class Task{
  public void go() {
      current = 0;
      final SwingWorker worker = new SwingWorker() {
          public Object construct() {
              return new ActualTask();
          }
      };
  }

  class ActualTask {
      ActualTask() {
          try {
              Thread.sleep(1000);
          } catch (InterruptedException e) {}
      }
  }
}

Task.java

5 Responses to “SwingWorker not on Java 6.0”

  1. Laird Nelson Says:

    But SwingWorker IS in Java 6.0.

  2. wsjoung Says:

    Right, it’s in Java6.0 but what if we do not want, and we do not want clients upgrade VM.

  3. Dave Says:

    That seems overly complex. Why not just create a Runnable and do SwingUtilities.invokeLater()?

  4. Thierry Says:

    SwingWorker for Java 1.4 is contributed by SUN :
    http://java.sun.com/products/jfc/tsc/articles/threads/src/SwingWorker.java

    A much better SwingWorker exists in 1.5 in the SwingLabs API:
    http://www.swinglabs.org/

  5. Blog bookmarks 04/26/2008 « My Diigo bookmarks Says:

    [...] SwingWorker not on Java 6.0 « {Complexity} [...]

Leave a Reply