Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Find event dispatch thread violations

We all know we should do all GUI related tasks from the event dispatch thread and that weird bugs can be introduced otherwise - I try to remember this rule but I must admit I've noticed a couple of places recently where I haven't.

Is there a way to identify all the violations of this rule so they can be fixed? I've seen that there's a relevant findbugs rule here but it doesn't seem to catch all cases for me. Even throwing an exception whenever a violation occurs would be nice so I can fix it (or catch the exception and log the warning in case a user runs into a related issue.)

What approaches do people generally take with this?

like image 975
Michael Berry Avatar asked Dec 16 '11 01:12

Michael Berry


3 Answers

One approach is to install a custom repaint manager which detects and logs when painting is performed on a thread other than the EDT. We use this approach on our project, adapted from the following blog: http://weblogs.java.net/blog/alexfromsun/archive/2006/02/debugging_swing.html. This will not detect all classes of EDT thread violations, but it's definitely much better than nothing.

Update:

As a commenter pointed out, the linked web page is no longer available. Here is my code adapted from the blog posting:

import javax.swing.JComponent;
import javax.swing.RepaintManager;
import javax.swing.SwingUtilities;
import org.apache.log4j.Logger;
import sun.awt.AppContext;

public class DetectEdtViolationRepaintManager extends RepaintManager {

  private static final Logger LOGGER = Logger.getLogger(
    DetectEdtViolationRepaintManager.class);

  /**
   * Used to ensure we only print a stack trace once per abusing thread.  May
   * be null if the option is disabled.
   */
  private ThreadLocal alreadyWarnedLocal;

  /**
   * Installs a new instance of DetectEdtViolationRepaintManager which does not
   * warn repeatedly, as the current repaint manager.
   */
  public static void install() {
    install(false);
  }

  /**
   * Installs a new instance of DetectEdtViolationRepaintManager as the current
   * repaint manager.
   * @param warnRepeatedly whether multiple warnings should be logged for each
   *        violating thread
   */
  public static void install(boolean warnRepeatedly) {
    AppContext.getAppContext().put(RepaintManager.class, 
      new DetectEdtViolationRepaintManager(warnRepeatedly));
    LOGGER.info("Installed new DetectEdtViolationRepaintManager");
  }

  /**
   * Creates a new instance of DetectEdtViolationRepaintManager.
   * @param warnRepeatedly whether multiple warnings should be logged for each
   *        violating thread
   */
  private DetectEdtViolationRepaintManager(boolean warnRepeatedly) {
    if (!warnRepeatedly) {
      this.alreadyWarnedLocal = new ThreadLocal();
    }
  }

  /**
   * {@inheritDoc}
   */
  public synchronized void addInvalidComponent(JComponent component) {
    checkThreadViolations();
    super.addInvalidComponent(component);
  }

  /**
   * {@inheritDoc}
   */
  public synchronized void addDirtyRegion(JComponent component, int x, int y, 
    int w, int h) {
    checkThreadViolations();
    super.addDirtyRegion(component, x, y, w, h);
  }

  /**
   * Checks if the calling thread is called in the event dispatch thread.
   * If not an exception will be printed to the console.
   */
  private void checkThreadViolations() {
    if (alreadyWarnedLocal != null && Boolean.TRUE.equals(alreadyWarnedLocal.get())) {
      return;
    }
    if (!SwingUtilities.isEventDispatchThread()) {
      if (alreadyWarnedLocal != null) {
        alreadyWarnedLocal.set(Boolean.TRUE);
      }
      LOGGER.warn("painting on non-EDT thread", new Exception());
    }
  }
}
like image 113
JimN Avatar answered Oct 03 '22 23:10

JimN


I just try to be careful, myself. But you could install code to test whether a given piece of code was executing in the dispatch thread with SwingUtilities.isEventDispatchThread(), and do what you like if it isn't (or if it is).

like image 45
arcy Avatar answered Oct 03 '22 23:10

arcy


The Substance Look and Feel includes an automatic runtime EDT violation checker. It can help catching EDT violations when testing. It throws an IllegalStateException when a violation is detected. It's good for testing.

like image 27
prunge Avatar answered Oct 04 '22 00:10

prunge