5

イベントディスパッチスレッドからすべてのGUI関連のタスクを実行する必要があり、それ以外の場合は奇妙なバグが発生する可能性があることは誰もが知っています。このルールを覚えようとしていますが、最近、気付いていない場所がいくつかあることを認めなければなりません。

このルールのすべての違反を特定して修正できるようにする方法はありますか?ここに関連するfindbugsルールがあることを確認しましたが、すべてのケースを捉えているわけではないようです。違反が発生するたびに例外をスローすることもできれば、それを修正できます(または、例外をキャッチして、ユーザーが関連する問題に遭遇した場合に備えて警告をログに記録できます)。

人々はこれに対して一般的にどのようなアプローチを取りますか?

4

4 に答える 4

6

1つのアプローチは、EDT以外のスレッドでペイントが実行されたときに検出してログに記録するカスタム再ペイントマネージャーをインストールすることです。このアプローチは、次のブログから採用したプロジェクトで使用しています:http ://weblogs.java.net/blog/alexfromsun/archive/2006/02/debugging_swing.html 。これは、EDTスレッド違反のすべてのクラスを検出するわけではありませんが、何もないよりは間違いなくはるかに優れています。

アップデート:

コメント提供者が指摘したように、リンクされたWebページは使用できなくなりました。これがブログ投稿から適応した私のコードです:

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());
    }
  }
}
于 2011-12-16T03:18:50.433 に答える
4

私自身、気をつけようとしています。ただし、SwingUtilities.isEventDispatchThread()を使用して、特定のコードがディスパッチスレッドで実行されているかどうかをテストするコードをインストールし、実行されていない場合(または実行されている場合)に実行できます。

于 2011-12-16T01:55:12.997 に答える
3

サブスタンスルックアンドフィールには、自動ランタイムEDT違反チェッカーが含まれています。テスト時にEDT違反をキャッチするのに役立ちます。違反が検出されると、IllegalStateExceptionがスローされます。テストに適しています。

于 2011-12-16T01:58:48.280 に答える
0

Festのswingモジュールには、インストール可能なEDT違反チェッカーも含まれています。これは、違反を検出すると例外をスローします。

于 2013-12-17T16:20:48.410 に答える