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

Advertisements

5 Responses to “SwingWorker not on Java 6.0”

  1. But SwingWorker IS in Java 6.0.

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

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

  4. 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. […] SwingWorker not on Java 6.0 « {Complexity} […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: