如何检测Swing线程策略违规

11

我正在寻找一种自动检测Swing单线程策略在我的代码中违规的方法。我希望有一些类似于AOP代码的东西,可以在swing应用程序运行时将其投入到VM中,并记录任何在EDT之外修改swing组件的地方。

虽然我不是AOP专家,但我想象创建一个环绕每个java.swing.*类的AOP代理可能会像这样:

AOP_before(Method m, Object args[]) {
 if (!isEventDispatchThread(Thread.currentThread()) {
  logStack(new RuntimeException("violation!"));
 }

 invoke(m, args);
}

有没有人知道一个能做到这一点的项目或工具?


我之前回答过类似的问题,并提供了AOP代码。有什么建议我该如何找到它?我已经尝试了显而易见的Google和SO搜索。 - mdma
1
我建议在代码中保持清晰的分离,将应该在EDT上运行的代码与不应该在EDT上运行的代码分开。尽量避免将应该在EDT上运行的代码和不应该在EDT上运行的代码组合在一起,即使看起来像是一种捷径。 - Tom Hawtin - tackline
@mdma,只需点击您的用户名,即可查看您回答过的问题列表。 - Mike Daniels
3个回答

8

我没有使用过这个特定的工具,但是CheckThreadViolationRepaintManager应该可以解决问题。

它需要添加以下内容:

RepaintManager.setCurrentManager(new CheckThreadViolationRepaintManager());

然而,您需要将其添加到您的代码中。

这个效果还不错。我已经发现了一些违规行为。 - Justin
链接的代码基于另一个人的一些早期工作。该代码包括指向他不存在的博客文章的链接。我在WaybackMachine上找到了一份副本,并发现它是一篇有趣的文章。以下是原作者关于RepaintManager解决方案的博客文章的永久存档版本链接:http://web.archive.org/web/20071212214347/http://www.clientjava.com/blog/2004/08/31/1093972473000.html - JVMATL

4

为了后人的方便,这里提供了TofuBeer发现的CheckThreadViolationRepaintManager的简化版本。

RepaintManager.setCurrentManager(new RepaintManager() {
   public synchronized void addInvalidComponent( JComponent component ) {
     check( component );
     super.addInvalidComponent( component );
   }
   public void addDirtyRegion( JComponent component, int x, int y, int w, int h ) {
     check( component );
     super.addDirtyRegion( component, x, y, w, h );
   }
   private void check( JComponent c ) {
     if( !SwingUtilities.isEventDispatchThread() && c.isShowing() ) {
        new Throwable("EDT required!").printStackTrace();
     }
   }
});

只需在主方法中调用此方法,即可在非EDT线程上更改组件时记录堆栈跟踪日志。

3
我发现了一篇4年前的博客文章,描述了一些解决方案,但如果您找到一个能够检测出最多EDT违规的解决方案,我会非常感兴趣。RepaintManager似乎无法完全检测所有违规行为。

RepaintManager 无法检测哪些情况尚未确定? - Justin
这些解决方案看起来非常不错,但更难快速实现。 - Justin
你还有链接吗?你提供的那个已经失效了。 - peterboston

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接