5 Stimmen

Verstöße gegen den Ereignisverteilungs-Thread finden

Wir alle wissen, dass wir alle GUI-bezogenen Aufgaben vom Event-Dispatch-Thread aus erledigen sollten und dass andernfalls seltsame Fehler auftreten können - ich versuche, mich an diese Regel zu erinnern, aber ich muss zugeben, dass mir in letzter Zeit einige Stellen aufgefallen sind, an denen ich das nicht getan habe.

Gibt es eine Möglichkeit, alle Verstöße gegen diese Regel zu ermitteln, damit sie behoben werden können? Ich habe gesehen, dass es eine entsprechende Findbugs-Regel gibt aquí aber es scheint bei mir nicht alle Fälle zu erfassen. Sogar das Auslösen einer Ausnahme, wenn eine Verletzung auftritt, wäre schön, damit ich sie beheben kann (oder die Ausnahme abfangen und die Warnung protokollieren kann, falls ein Benutzer auf ein ähnliches Problem stößt).

Wie gehen die Menschen im Allgemeinen damit um?

6voto

JimN Punkte 3108

Ein Ansatz besteht darin, einen benutzerdefinierten Repaint-Manager zu installieren, der erkennt und protokolliert, wenn ein Malvorgang auf einem anderen Thread als dem EDT ausgeführt wird. Wir verwenden diesen Ansatz in unserem Projekt, angepasst an den folgenden Blog: http://weblogs.java.net/blog/alexfromsun/archive/2006/02/debugging_swing.html . Damit werden zwar nicht alle Klassen von EDT-Thread-Verletzungen erkannt, aber es ist auf jeden Fall besser als nichts.

Aktualisierung:

Wie ein Kommentator bemerkte, ist die verlinkte Webseite nicht mehr verfügbar. Hier ist mein Code aus dem Blogbeitrag angepasst:

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());
    }
  }
}

4voto

arcy Punkte 12464

Ich selbst versuche nur, vorsichtig zu sein. Aber Sie könnten Code installieren, um zu testen, ob ein bestimmtes Stück Code im Dispatch-Thread mit SwingUtilities.isEventDispatchThread() ausgeführt wird, und tun, was Sie wollen, wenn es nicht der Fall ist (oder wenn es der Fall ist).

3voto

prunge Punkte 21529

En Aussehen und Wirkung der Substanz beinhaltet eine automatische Laufzeit-EDT-Verletzungschecker . Es kann helfen, EDT-Verletzungen beim Testen zu erkennen. Sie löst eine IllegalStateException aus, wenn eine Verletzung festgestellt wird. Es ist gut zum Testen.

0voto

Ian Jones Punkte 1968

Fest's swing module umfasst auch eine EDT-Verstoß-Prüfer installieren, das eine Ausnahme auslöst, wenn es einen Verstoß feststellt.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X