Java/Swing JFC/SwingWorker

Материал из Java эксперт
Версия от 06:42, 1 июня 2010; Admin (обсуждение | вклад) (1 версия)
(разн.) ← Предыдущая | Текущая версия (разн.) | Следующая → (разн.)
Перейти к: навигация, поиск

3rd version of SwingWorker

   
//revised from arsenal
import javax.swing.SwingUtilities;
/**
 * This is the 3rd version of SwingWorker (also known as
 * SwingWorker 3), an abstract class that you subclass to
 * perform GUI-related work in a dedicated thread.  For
 * instructions on and examples of using this class, see:
 * 
 * http://java.sun.ru/docs/books/tutorial/uiswing/misc/threads.html
 *
 * Note that the API changed slightly in the 3rd version:
 * You must now invoke start() on the SwingWorker after
 * creating it.
 */
public abstract class SwingWorker {
    private Object value;  // see getValue(), setValue()
    /** 
     * Class to maintain reference to current worker thread
     * under separate synchronization control.
     */
    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;
    /** 
     * Get the value produced by the worker thread, or null if it 
     * hasn"t been constructed yet.
     */
    protected synchronized Object getValue() { 
        return value; 
    }
    /** 
     * Set the value produced by worker thread 
     */
    private synchronized void setValue(Object x) { 
        value = x; 
    }
    /** 
     * Compute the value to be returned by the <code>get</code> method. 
     */
    public abstract Object construct();
    /**
     * Called on the event dispatching thread (not on the worker thread)
     * after the <code>construct</code> method has returned.
     */
    public void finished() {
    }
    /**
     * A new method that interrupts the worker thread.  Call this method
     * to force the worker to stop what it"s doing.
     */
    public void interrupt() {
        Thread t = threadVar.get();
        if (t != null) {
            t.interrupt();
        }
        threadVar.clear();
    }
    /**
     * Return the value created by the <code>construct</code> method.  
     * Returns null if either the constructing thread or the current
     * thread was interrupted before a value was produced.
     * 
     * @return the value created by the <code>construct</code> method
     */
    public Object get() {
        while (true) {  
            Thread t = threadVar.get();
            if (t == null) {
                return getValue();
            }
            try {
                t.join();
            }
            catch (InterruptedException e) {
                Thread.currentThread().interrupt(); // propagate
                return null;
            }
        }
    }

    /**
     * Start a thread that will call the <code>construct</code> method
     * and then exit.
     */
    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);
    }
    /**
     * Start the worker thread.
     */
    public void start() {
        Thread t = threadVar.get();
        if (t != null) {
            t.start();
        }
    }
}





A pool of work threads

   
/*
 * WorkThreadPool.java - Background thread pool that does stuff
 * :tabSize=8:indentSize=8:noTabs=false:
 * :folding=explicit:collapseFolds=1:
 *
 * Copyright (C) 2000 Slava Pestov
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
//{{{ Imports
import java.util.EventListener;
import javax.swing.SwingUtilities;
import javax.swing.event.EventListenerList;
//}}}
/**
 * A pool of work threads.
 * 
 * @author Slava Pestov
 * @version $Id: WorkThreadPool.java 12504 2008-04-22 23:12:43Z ezust $
 * @see org.gjt.sp.util.WorkThread
 * @since jEdit 2.6pre1
 */
public class WorkThreadPool {
  // {{{ WorkThreadPool constructor
  /**
   * Creates a new work thread pool with the specified number of work threads.
   * 
   * @param name
   *          The thread name prefix
   * @param count
   *          The number of work threads
   */
  public WorkThreadPool(String name, int count) {
    listenerList = new EventListenerList();
    if (count != 0) {
      threadGroup = new ThreadGroup(name);
      threads = new WorkThread[count];
      for (int i = 0; i < threads.length; i++) {
        threads[i] = new WorkThread(this, threadGroup, name + " #" + (i + 1));
      }
    }
  } // }}}
  // {{{ start() method
  /**
   * Starts all the threads in this thread pool.
   */
  public void start() {
    /* not really needed since threads don"t start until after */
    synchronized (lock) {
      started = true;
      if (awtRequestCount != 0 && requestCount == 0)
        queueAWTRunner();
    }
    if (threads != null) {
      for (int i = 0; i < threads.length; i++) {
        threads[i].start();
      }
    }
  } // }}}
  // {{{ addWorkRequest() method
  /**
   * Adds a work request to the queue.
   * 
   * @param run
   *          The runnable
   * @param inAWT
   *          If true, will be executed in AWT thread. Otherwise, will be
   *          executed in work thread
   */
  public void addWorkRequest(Runnable run, boolean inAWT) {
    if (threads == null) {
      run.run();
      return;
    }
    synchronized (lock) {
      // {{{ if there are no requests, execute AWT requests immediately
      if (started && inAWT && requestCount == 0 && awtRequestCount == 0) {
        // Log.log(Log.DEBUG,this,"AWT immediate: " + run);
        if (SwingUtilities.isEventDispatchThread())
          run.run();
        else
          SwingUtilities.invokeLater(run);
        return;
      } // }}}
      Request request = new Request(run);
      // {{{ Add to AWT queue...
      if (inAWT) {
        if (firstAWTRequest == null && lastAWTRequest == null)
          firstAWTRequest = lastAWTRequest = request;
        else {
          lastAWTRequest.next = request;
          lastAWTRequest = request;
        }
        awtRequestCount++;
        // if no requests are running, requestDone()
        // will not be called, so we must queue the
        // AWT runner ourselves.
        if (started && requestCount == 0)
          queueAWTRunner();
      } // }}}
      // {{{ Add to work thread queue...
      else {
        if (firstRequest == null && lastRequest == null)
          firstRequest = lastRequest = request;
        else {
          lastRequest.next = request;
          lastRequest = request;
        }
        requestCount++;
      } // }}}
      lock.notifyAll();
    }
  } // }}}
  // {{{ waitForRequests() method
  /**
   * Waits until all requests are complete.
   */
  public void waitForRequests() {
    if (threads == null)
      return;
    synchronized (waitForAllLock) {
      while (requestCount != 0) {
        try {
          waitForAllLock.wait();
        } catch (InterruptedException ie) {
        }
      }
    }
    if (SwingUtilities.isEventDispatchThread()) {
      // do any queued AWT runnables
      doAWTRequests();
    } else {
      try {
        SwingUtilities.invokeAndWait(new RunRequestsInAWTThread());
      } catch (Exception e) {
      }
    }
  } // }}}
  // {{{ getRequestCount() method
  /**
   * Returns the number of pending requests.
   * 
   * @return the pending request count
   */
  public int getRequestCount() {
    return requestCount;
  } // }}}
  // {{{ getThreadCount() method
  /**
   * Returns the number of threads in this pool.
   * 
   * @return the thread count
   */
  public int getThreadCount() {
    if (threads == null)
      return 0;
    else
      return threads.length;
  } // }}}
  // {{{ getThread() method
  /**
   * Returns the specified thread.
   * 
   * @param index
   *          The index of the thread
   * @return a WorkThread
   */
  public WorkThread getThread(int index) {
    return threads[index];
  } // }}}
  // {{{ addProgressListener() method
  /**
   * Adds a progress listener to this thread pool.
   * 
   * @param listener
   *          The listener
   */
  public void addProgressListener(WorkThreadProgressListener listener) {
    listenerList.add(WorkThreadProgressListener.class, listener);
  } // }}}
  // {{{ removeProgressListener() method
  /**
   * Removes a progress listener from this thread pool.
   * 
   * @param listener
   *          The listener
   */
  public void removeProgressListener(WorkThreadProgressListener listener) {
    listenerList.remove(WorkThreadProgressListener.class, listener);
  } // }}}
  // {{{ Package-private members
  final Object lock = new Object();
  final Object waitForAllLock = new Object();
  // {{{ fireStatusChanged() method
  void fireStatusChanged(WorkThread thread) {
    final Object[] listeners = listenerList.getListenerList();
    if (listeners.length != 0) {
      int index = 0;
      for (int i = 0; i < threads.length; i++) {
        if (threads[i] == thread) {
          index = i;
          break;
        }
      }
      for (int i = listeners.length - 2; i >= 0; i--) {
        if (listeners[i] == WorkThreadProgressListener.class) {
          ((WorkThreadProgressListener) listeners[i + 1]).statusUpdate(WorkThreadPool.this, index);
        }
      }
    }
  } // }}}
  // {{{ fireProgressChanged() method
  void fireProgressChanged(WorkThread thread) {
    final Object[] listeners = listenerList.getListenerList();
    if (listeners.length != 0) {
      int index = 0;
      for (int i = 0; i < threads.length; i++) {
        if (threads[i] == thread) {
          index = i;
          break;
        }
      }
      for (int i = listeners.length - 2; i >= 0; i--) {
        if (listeners[i] == WorkThreadProgressListener.class) {
          ((WorkThreadProgressListener) listeners[i + 1])
              .progressUpdate(WorkThreadPool.this, index);
        }
      }
    }
  } // }}}
  // {{{ requestDone() method
  void requestDone() {
    synchronized (lock) {
      requestCount--;
      if (requestCount == 0 && firstAWTRequest != null)
        queueAWTRunner();
    }
  } // }}}
  // {{{ getNextRequest() method
  Request getNextRequest() {
    synchronized (lock) {
      Request request = firstRequest;
      if (request == null)
        return null;
      firstRequest = firstRequest.next;
      if (firstRequest == null)
        lastRequest = null;
      if (request.alreadyRun)
        throw new InternalError("AIEE!!! Request run twice!!! " + request.run);
      request.alreadyRun = true;
      /*
       * StringBuffer buf = new StringBuffer("request queue is now: "); Request
       * _request = request.next; while(_request != null) {
       * buf.append(_request.id); if(_request.next != null) buf.append(",");
       * _request = _request.next; } Log.log(Log.DEBUG,this,buf.toString());
       */
      return request;
    }
  } // }}}
  // }}}
  // {{{ Private members
  // {{{ Instance variables
  private boolean started;
  private ThreadGroup threadGroup;
  private WorkThread[] threads;
  // Request queue
  private Request firstRequest;
  private Request lastRequest;
  private int requestCount;
  // AWT thread magic
  private boolean awtRunnerQueued;
  private Request firstAWTRequest;
  private Request lastAWTRequest;
  private int awtRequestCount;
  private EventListenerList listenerList;
  // }}}
  // {{{ doAWTRequests() method
  /** Must always be called with the lock held. */
  private void doAWTRequests() {
    while (requestCount == 0 && firstAWTRequest != null) {
      doAWTRequest(getNextAWTRequest());
    }
  } // }}}
  // {{{ doAWTRequest() method
  /**
   * Must always be called with the lock held.
   * 
   * @param request
   *          the request to run
   */
  private void doAWTRequest(Request request) {
    // Log.log(Log.DEBUG,this,"Running in AWT thread: " + request);
    try {
      request.run.run();
    } catch (Throwable t) {
    }
    awtRequestCount--;
  } // }}}
  // {{{ queueAWTRunner() method
  /** Must always be called with the lock held. */
  private void queueAWTRunner() {
    if (!awtRunnerQueued) {
      awtRunnerQueued = true;
      SwingUtilities.invokeLater(new RunRequestsInAWTThread());
      // Log.log(Log.DEBUG,this,"AWT runner queued");
    }
  } // }}}
  // {{{ getNextAWTRequest() method
  private Request getNextAWTRequest() {
    Request request = firstAWTRequest;
    firstAWTRequest = firstAWTRequest.next;
    if (firstAWTRequest == null)
      lastAWTRequest = null;
    if (request.alreadyRun)
      throw new InternalError("AIEE!!! Request run twice!!! " + request.run);
    request.alreadyRun = true;
    /*
     * StringBuffer buf = new StringBuffer("AWT request queue is now: ");
     * Request _request = request.next; while(_request != null) {
     * buf.append(_request.id); if(_request.next != null) buf.append(",");
     * _request = _request.next; } Log.log(Log.DEBUG,this,buf.toString());
     */
    return request;
  } // }}}
  // }}}
  static int ID;
  // {{{ Request class
  static class Request {
    int id = ++ID;
    Runnable run;
    boolean alreadyRun;
    Request next;
    Request(Runnable run) {
      this.run = run;
    }
    public String toString() {
      return "[id=" + id + ",run=" + run + "]";
    }
  } // }}}
  // {{{ RunRequestsInAWTThread class
  class RunRequestsInAWTThread implements Runnable {
    public void run() {
      synchronized (lock) {
        awtRunnerQueued = false;
        if (requestCount == 0)
          doAWTRequests();
      }
    }
  } // }}}
}
/*
 * WorkThread.java - Background thread that does stuff Copyright (C) 2000 Slava
 * Pestov
 * 
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or any later version.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 * Place - Suite 330, Boston, MA 02111-1307, USA.
 */
/**
 * Services work requests in the background.
 * 
 * @author Slava Pestov
 * @version $Id: WorkThread.java 12504 2008-04-22 23:12:43Z ezust $
 */
class WorkThread extends Thread implements ThreadAbortMonitor {
  public WorkThread(WorkThreadPool pool, ThreadGroup group, String name) {
    super(group, name);
    // so that jEdit doesn"t exit with no views open automatically
    // setDaemon(true);
    setPriority(Thread.MIN_PRIORITY);
    this.pool = pool;
  }
  /**
   * Sets if the current request can be aborted. If set to true and already
   * aborted, the thread will be stopped
   * 
   * @param abortable
   *          true if the WorkThread is abortable
   * @since jEdit 2.6pre1
   */
  public void setAbortable(boolean abortable) {
    synchronized (abortLock) {
      this.abortable = abortable;
      if (aborted)
        stop(new Abort());
    }
  }
  /**
   * Returns if the work thread is currently running a request.
   * 
   * @return true if a request is currently running
   */
  public boolean isRequestRunning() {
    return requestRunning;
  }
  public boolean isAborted() {
    synchronized (abortLock) {
      return aborted;
    }
  }
  /**
   * Returns the status text.
   * 
   * @return the status label
   */
  public String getStatus() {
    return status;
  }
  /**
   * Sets the status text.
   * 
   * @param status
   *          the new status of the thread
   * @since jEdit 2.6pre1
   */
  public void setStatus(String status) {
    this.status = status;
    pool.fireProgressChanged(this);
  }
  /**
   * Returns the progress value.
   * 
   * @return the progress value
   */
  public int getProgressValue() {
    return progressValue;
  }
  /**
   * Sets the progress value.
   * 
   * @param progressValue
   *          the new progress value
   * @since jEdit 2.6pre1
   */
  public void setProgressValue(int progressValue) {
    this.progressValue = progressValue;
    pool.fireProgressChanged(this);
  }
  /**
   * Returns the progress maximum.
   * 
   * @return the maximum value of the progression
   */
  public int getProgressMaximum() {
    return progressMaximum;
  }
  /**
   * Sets the maximum progress value.
   * 
   * @param progressMaximum
   *          the maximum value of the progression
   * @since jEdit 2.6pre1
   */
  public void setProgressMaximum(int progressMaximum) {
    this.progressMaximum = progressMaximum;
    pool.fireProgressChanged(this);
  }
  /**
   * Aborts the currently running request, if allowed.
   * 
   * @since jEdit 2.6pre1
   */
  public void abortCurrentRequest() {
    synchronized (abortLock) {
      if (abortable && !aborted)
        stop(new Abort());
      aborted = true;
    }
  }
  public void run() {
    for (;;) {
      doRequests();
    }
  }
  // private members
  private WorkThreadPool pool;
  private final Object abortLock = new Object();
  private boolean requestRunning;
  private boolean abortable;
  private boolean aborted;
  private String status;
  private int progressValue;
  private int progressMaximum;
  private void doRequests() {
    WorkThreadPool.Request request;
    for (;;) {
      request = pool.getNextRequest();
      if (request == null)
        break;
      else {
        requestRunning = true;
        pool.fireStatusChanged(this);
        doRequest(request);
        requestRunning = false;
      }
    }
    pool.fireStatusChanged(this);
    synchronized (pool.waitForAllLock) {
      // notify a running waitForRequests() method
      pool.waitForAllLock.notifyAll();
    }
    synchronized (pool.lock) {
      // wait for more requests
      try {
        pool.lock.wait();
      } catch (InterruptedException ie) {
      }
    }
  }
  private void doRequest(WorkThreadPool.Request request) {
    try {
      request.run.run();
    } catch (Throwable t) {
    } finally {
      synchronized (abortLock) {
        aborted = abortable = false;
      }
      status = null;
      progressValue = progressMaximum = 0;
      pool.requestDone();
      pool.fireStatusChanged(this);
    }
  }
  public static class Abort extends Error {
    public Abort() {
      super("Work request aborted");
    }
  }
}
/*
 * ThreadAbortMonitor.java - Thread Abort Monitor
 * :tabSize=8:indentSize=8:noTabs=false: :folding=explicit:collapseFolds=1:
 * 
 * Copyright (C) 2006 Matthieu Casanova
 * 
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or any later version.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 * Place - Suite 330, Boston, MA 02111-1307, USA.
 */
/**
 * @author Matthieu Casanova
 * @author $Id: VFS.java 7129 2006-09-25 20:05:57Z kpouer $
 */
interface ThreadAbortMonitor {
  boolean isAborted();
}
/*
 * WorkThreadProgressListener.java - Progress listener Copyright (C) 2000 Slava
 * Pestov
 * 
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or any later version.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 * Place - Suite 330, Boston, MA 02111-1307, USA.
 */
/**
 * A work thread execution progress listener.
 * 
 * @since jEdit 2.6pre1
 */
interface WorkThreadProgressListener extends EventListener {
  // status message changed, operation started, operation ends, ...
  void statusUpdate(WorkThreadPool threadPool, int threadIndex);
  // progress bar value change
  void progressUpdate(WorkThreadPool threadPool, int threadIndex);
}





Detect Event Dispatch Thread rule violations

 
/*
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */
import java.lang.ref.WeakReference;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.RepaintManager;
import javax.swing.SwingUtilities;
/**
 * <p>
 * This class is used to detect Event Dispatch Thread rule violations<br>
 * See 
 * </p>
 * 
 * @author Scott Delap
 * @author Alexander Potochkin
 * 
 * https://swinghelper.dev.java.net/
 */
public class CheckThreadViolationRepaintManager extends RepaintManager {
  // it is recommended to pass the complete check
  private boolean completeCheck = true;
  private WeakReference<JComponent> lastComponent;
  public CheckThreadViolationRepaintManager(boolean completeCheck) {
    this.rupleteCheck = completeCheck;
  }
  public CheckThreadViolationRepaintManager() {
    this(true);
  }
  public boolean isCompleteCheck() {
    return completeCheck;
  }
  public void setCompleteCheck(boolean completeCheck) {
    this.rupleteCheck = completeCheck;
  }
  public synchronized void addInvalidComponent(JComponent component) {
    checkThreadViolations(component);
    super.addInvalidComponent(component);
  }
  public void addDirtyRegion(JComponent component, int x, int y, int w, int h) {
    checkThreadViolations(component);
    super.addDirtyRegion(component, x, y, w, h);
  }
  private void checkThreadViolations(JComponent c) {
    if (!SwingUtilities.isEventDispatchThread() && (completeCheck || c.isShowing())) {
      boolean repaint = false;
      boolean fromSwing = false;
      boolean imageUpdate = false;
      StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
      for (StackTraceElement st : stackTrace) {
        if (repaint && st.getClassName().startsWith("javax.swing.")) {
          fromSwing = true;
        }
        if (repaint && "imageUpdate".equals(st.getMethodName())) {
          imageUpdate = true;
        }
        if ("repaint".equals(st.getMethodName())) {
          repaint = true;
          fromSwing = false;
        }
      }
      if (imageUpdate) {
        // assuming it is java.awt.image.ImageObserver.imageUpdate(...)
        // image was asynchronously updated, that"s ok
        return;
      }
      if (repaint && !fromSwing) {
        // no problems here, since repaint() is thread safe
        return;
      }
      // ignore the last processed component
      if (lastComponent != null && c == lastComponent.get()) {
        return;
      }
      lastComponent = new WeakReference<JComponent>(c);
      violationFound(c, stackTrace);
    }
  }
  protected void violationFound(JComponent c, StackTraceElement[] stackTrace) {
    System.out.println();
    System.out.println("EDT violation detected");
    System.out.println(c);
    for (StackTraceElement st : stackTrace) {
      System.out.println("\tat " + st);
    }
  }
  public static void main(String[] args) throws Exception {
    // set CheckThreadViolationRepaintManager
    RepaintManager.setCurrentManager(new CheckThreadViolationRepaintManager());
    // Valid code
    SwingUtilities.invokeAndWait(new Runnable() {
      public void run() {
        test();
      }
    });
    System.out.println("Valid code passed...");
    repaintTest();
    System.out.println("Repaint test - correct code");
    // Invalide code (stack trace expected)
    test();
  }
  static void test() {
    JFrame frame = new JFrame("Am I on EDT?");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.add(new JButton("JButton"));
    frame.pack();
    frame.setVisible(true);
    frame.dispose();
  }
  // this test must pass
  static void imageUpdateTest() {
    JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    JEditorPane editor = new JEditorPane();
    frame.setContentPane(editor);
    editor.setContentType("text/html");
    // it works with no valid image as well
    editor.setText("<html><img src=\"file:\\lala.png\"></html>");
    frame.setSize(300, 200);
    frame.setVisible(true);
  }
  private static JButton test;
  static void repaintTest() {
    try {
      SwingUtilities.invokeAndWait(new Runnable() {
        public void run() {
          test = new JButton();
          test.setSize(100, 100);
        }
      });
    } catch (Exception e) {
      e.printStackTrace();
    }
    // repaint(Rectangle) should be ok
    test.repaint(test.getBounds());
    test.repaint(0, 0, 100, 100);
    test.repaint();
  }
}





Generic class to dispatch events in a highly reliable way.

 
/*
   Licensed to the Apache Software Foundation (ASF) under one or more
   contributor license agreements.  See the NOTICE file distributed with
   this work for additional information regarding copyright ownership.
   The ASF licenses this file to You under the Apache License, Version 2.0
   (the "License"); you may not use this file except in compliance with
   the License.  You may obtain a copy of the License at
       http://www.apache.org/licenses/LICENSE-2.0
   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
 */
import java.awt.EventQueue;
import java.util.List;
import java.lang.reflect.InvocationTargetException;
/**
 * Generic class to dispatch events in a highly reliable way.
 *
 * @author 
 * @version $Id: EventDispatcher.java 579228 2007-09-25 12:50:46Z cam $
 */
public class EventDispatcher {
    public interface Dispatcher {
        void dispatch(Object listener,
                             Object event);
    }

    public static void fireEvent(final Dispatcher dispatcher,
                                 final List listeners,
                                 final Object evt,
                                 final boolean useEventQueue) {
        if (useEventQueue && !EventQueue.isDispatchThread()) {
            Runnable r = new Runnable() {
                    public void run() {
                        fireEvent(dispatcher, listeners, evt, useEventQueue);
                    }
                };
            try {
                EventQueue.invokeAndWait(r);
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (InterruptedException e) {
                // Assume they will get delivered????
                // be nice to wait on List but how???
            } catch (ThreadDeath td) {
                throw td;
            } catch (Throwable t) {
                t.printStackTrace();
            }
            return;
        }
        Object [] ll = null;
        Throwable err = null;
        int retryCount = 10;
        while (--retryCount != 0) {
            // If the thread has been interrupted this can "mess up"
            // the class loader and cause this otherwise safe code to
            // throw errors.
            try {
                synchronized (listeners) {
                    if (listeners.size() == 0)
                        return;
                    ll = listeners.toArray();
                    break;
                }
            } catch(Throwable t) {
                err = t;
            }
        }
        if (ll == null) {
            if (err != null)
                err.printStackTrace();
            return;
        }
        dispatchEvent(dispatcher, ll, evt);
    }
    protected static void dispatchEvent(final Dispatcher dispatcher,
                                        final Object [] ll,
                                        final Object evt) {
        ThreadDeath td = null;
        try {
            for (int i = 0; i < ll.length; i++) {
                try {
                    Object l;
                    synchronized (ll) {
                        l = ll[i];
                        if (l == null) continue;
                        ll[i] = null;
                    }
                    dispatcher.dispatch(l, evt);
                } catch (ThreadDeath t) {
                    // Keep delivering messages but remember to throw later.
                    td = t;
                } catch (Throwable t) {
                    t.printStackTrace();
                }
            }
        } catch (ThreadDeath t) {
            // Remember to throw later.
            td = t;
        } catch (Throwable t) {
            if (ll[ll.length-1] != null)
                dispatchEvent(dispatcher, ll, evt);
            t.printStackTrace();
        }
        if (td != null) throw td;
    }
}





Process On Swing Event Thread

   
/*
 * Copyright (C) 2001-2004 Colin Bell
 * colbell@users.sourceforge.net
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

import java.awt.ruponent;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Frame;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.geom.Rectangle2D;
import java.beans.PropertyVetoException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.SwingUtilities;
/**
 * Common GUI utilities accessed via static methods.
 * 
 * @author 
 */
public class GUIUtils {

  public static void processOnSwingEventThread(Runnable todo) {
    processOnSwingEventThread(todo, false);
  }
  public static void processOnSwingEventThread(Runnable todo, boolean wait) {
    if (todo == null) {
      throw new IllegalArgumentException("Runnable == null");
    }
    if (wait) {
      if (SwingUtilities.isEventDispatchThread()) {
        todo.run();
      } else {
        try {
          SwingUtilities.invokeAndWait(todo);
        } catch (Exception ex) {
          throw new RuntimeException(ex);
        }
      }
    } else {
      if (SwingUtilities.isEventDispatchThread()) {
        todo.run();
      } else {
        SwingUtilities.invokeLater(todo);
      }
    }
  }
}





SwingWorker in Java 6

  
import java.awt.LayoutManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.List;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingWorker;
public class Main{
  public static void main(String[] args) {
    final JProgressBar progressBar = new JProgressBar(0, 10);
    final CounterTask task = new CounterTask();
    task.addPropertyChangeListener(new PropertyChangeListener() {
      public void propertyChange(PropertyChangeEvent evt) {
        if ("progress".equals(evt.getPropertyName())) {
          progressBar.setValue((Integer) evt.getNewValue());
        }
      }
    });
    JButton startButton = new JButton("Start");
    startButton.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        task.execute();
      }
    });
    JButton cancelButton = new JButton("Cancel");
    cancelButton.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        task.cancel(true);
      }
    });
    JPanel buttonPanel = new JPanel();
    buttonPanel.add(startButton);
    buttonPanel.add(cancelButton);
    JPanel cp = new JPanel();
    LayoutManager layout = new BoxLayout(cp, BoxLayout.Y_AXIS);
    cp.setLayout(layout);
    cp.add(buttonPanel);
    cp.add(progressBar);
    JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setContentPane(cp);
    frame.pack();
    frame.setVisible(true);
  }
}
class CounterTask extends SwingWorker<Integer, Integer> {
  int DELAY = 1000;
  @Override
  protected Integer doInBackground() throws Exception {
    int i = 0;
    int count = 10;
    while (!isCancelled() && i < count) {
      i++;
      publish(new Integer[] { i });
      setProgress(count * i / count);
      Thread.sleep(DELAY);
    }
    return count;
  }   
  protected void process(List<Integer> chunks) {
      System.out.println(chunks);
  }
  @Override
  protected void done() {
    if (isCancelled())
      System.out.println("Cancelled !");
    else
      System.out.println("Done !");
  }
}





Use SwingWorker to perform background tasks

   
 
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.SwingWorker;
public class Main extends JFrame {
  public Main() {
    this.setLayout(new FlowLayout());
    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    JButton processButton = new JButton("Start");
    JButton helloButton = new JButton("Hello");
    processButton.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent event) {
        MyTask process = new MyTask();
        try {
          process.execute();
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
    });
    helloButton.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        JOptionPane.showMessageDialog(null, "Hello There");
      }
    });
    this.getContentPane().add(processButton);
    this.getContentPane().add(helloButton);
    this.pack();
    setVisible(true);
  }
  public static void main(String[] args) {
    new Main();
  }
}
class MyTask extends SwingWorker {
  protected Object doInBackground() throws Exception {
    Integer result = new Integer(0);
    for (int i = 0; i < 10; i++) {
      result += i * 10;
      try {
        Thread.sleep(5000);
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
    return result;
  }
}





Use SwingWorker to wrap time consuming task

    
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.math.BigInteger;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingWorker;
public class PrimeCheck extends JFrame {
  public PrimeCheck() {
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    JPanel pnl = new JPanel();
    JButton btnCheck = new JButton("Check");
    ActionListener al;
    al = new ActionListener() {
      public void actionPerformed(ActionEvent ae) {
        try {
          BigInteger bi = new BigInteger("1234567");
          System.out.println("One moment...");
          new PrimeCheckTask(bi).execute();
        } catch (NumberFormatException nfe) {
          System.out.println("Invalid input");
        }
      }
    };
    btnCheck.addActionListener(al);
    pnl.add(btnCheck);
    getContentPane().add(pnl, BorderLayout.NORTH);
    pack();
    setResizable(false);
    setVisible(true);
  }
  public static void main(String[] args) {
        new PrimeCheck();
  }
}
class PrimeCheckTask extends SwingWorker<Boolean, Void> {
  private BigInteger bi;
  PrimeCheckTask(BigInteger bi) {
    this.bi = bi;
  }
  @Override
  public Boolean doInBackground() {
    return bi.isProbablePrime(1000);
  }
  @Override
  public void done() {
    try {
        boolean isPrime = get();
        if (isPrime)
          System.out.println("Integer is prime");
        else
          System.out.println("Integer is not prime");
    } catch (Exception ee) {
      System.out.println("Unable to determine primeness");
    }
  }
}