Find event dispatch thread violations
Asked Answered
S

4

5

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?

Salesperson answered 16/12, 2011 at 1:47 Comment(1)
See also this related Q&A.Delphinus
S
6

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());
    }
  }
}
Spiffing answered 16/12, 2011 at 3:18 Comment(2)
Thanks, that definitely looks promising - I'll take a look!Salesperson
the link doesn't work anymore. do you have the new address?Bureaucratic
B
4

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).

Bainbridge answered 16/12, 2011 at 1:55 Comment(0)
A
3

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.

Absorbing answered 16/12, 2011 at 1:58 Comment(1)
do you have any idea how to get the EDT violation checker (only) from its github?Bureaucratic
C
0

Fest's swing module also includes a EDT violtion checker you could install, which throws an exception when it detects a violation.

Canzona answered 17/12, 2013 at 16:20 Comment(1)
do you have the new address about the EDT violation checker? The old doesn't work anymore.Bureaucratic

© 2022 - 2024 — McMap. All rights reserved.