在运行时Swing验证Event Dispatch Thread上的代码

时间:2010-06-10 13:48:46

标签: java swing event-dispatch-thread

是否有任何库可以检测代码以验证在事件调度线程上调用Swing组件上调用的方法?编写一些用于执行此操作的基本代码可能不会太困难,但我确信存在边缘情况以及其他人处理的其他情况。我在运行时正在寻找这个,而不是单元测试。

4 个答案:

答案 0 :(得分:11)

FEST框架有一个工具来检测EDT的Swing使用情况。它基本上是您安装的RepaintManager。该框架面向测试,但RepaintManager可以在部署时使用。

或者,要检查所有方法(例如getter和setter只能在EDT上访问),可以使用AspectJ和加载时编织将SwingUtilities.isDisaptchThread()建议添加到swing组件上的每个方法(和JDK)摆动组件。)

@Aspect
public class EDTCheck {

    @Pointcut("call (* javax.swing..*+.*(..)) || " +
              "call (javax.swing..*+.new(..))")
    public void swingMethods() {}

    @Pointcut("call (* com.mystuff.swing..*+.*(..)) || " +
              "call (com.mystuff.swing..*+.new(..))")
    public void mySwingMethods() {}


    @Pointcut("call (* javax.swing..*+.add*Listener(..)) || " +
              "call (* javax.swing..*+.remove*Listener(..)) || " +
              "call (void javax.swing.JComponent+.setText(java.lang.String))")
    public void safeMethods() {}

    @Before("(swingMethods() || mySwingMethods()) && !safeMethods()")
    public void checkCallingThread(JoinPoint.StaticPart thisJoinPointStatic) {
        if(!SwingUtilities.isDispatchThread()) {
            System.out.println(
                    "Swing single thread rule violation: " 
                    + thisJoinPointStatic);
            Thread.dumpStack();
            // or you might throw an unchecked exception
        }
    }

}

(稍微修改了文章 - 添加了mySwingMethods切入点,并使用SwingUtiliites.isDispatchThread()。实际上它与EventQueue.isDispatchThread()相同,但抽象更清晰。)

答案 1 :(得分:2)

从编码的角度来看,明确区分EDT代码和非EDT代码。避免像瘟疫一样SwingWorker

要声明您在EDT上(插入!关闭),请添加以下行:

assert java.awt.EventQueue.isDispatchThread();

您需要-ea / -enableassertions才能执行此操作。但是,它主要用作可执行注释。

答案 2 :(得分:2)

我遇到了斯科特·德拉普(Scott Delap)的简单而聪明(尽管不完全是防弹)的方法 http://today.java.net/pub/a/today/2005/04/19/desktoplive.html

正如在上面的mdma的FEST答案中暗示的那样,可以使用自定义RepaintManger,只需覆盖方法

addInvalidComponent(JComponent component) 

addDirtyRegion(JComponent component, int x, int y, int w, int h)

并使用

SwingUtilities.isEventDispatchThread()

要检查我们是否使用AWT,您可以通过添加

轻松地将其集成到JUnit中
org.JUnit.Assert.fail("AWT Thread Violation")

在您的检查程序中。

这里的逻辑是大多数(但不是全部)Swing操作会导致重绘,最终在RepaintManager中调用这些方法,因此我们可以捕获这些并进行检查。

Alexander Potochkin在这里有各种各样的方法:http://weblogs.java.net/blog/alexfromsun/archive/2006/02/debugging_swing.html

答案 3 :(得分:1)

您只需要以下代码:

void method() {
    if (!SwingUtilities.isEventDispatchThread()) {
       SwingUtilities.invokeAndWait(new Runnable() { public void run() { method(); } );
       return;
    }

    // do method code here, guaranteed to be in EDT
}

此外,使用Substance作为你的LAF将帮助你找出在EDT上没有执行Swing相关内容的地方。它有适当的检查,以确保任何Swing的东西在正确的线程上完成,或者它失败并出现异常。