感谢所有的提示,这是最终我想出的解决方案。它比我想象的要简单。这个解决方案同时使用了AspectJ和Annotations。它的工作原理是这样的:只需将以下注释(定义如下)之一添加到方法或类中,并在开头插入一个简单的EDT规则违规检查。特别是如果像这样标记整个类,您可以仅使用极少量的额外代码进行大量测试。
首先,我下载了
AspectJ并将其添加到我的项目中(在Eclipse中,您可以使用
AJDT)。
然后,我定义了两个新的注释:
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
@Target({ElementType.METHOD, ElementType.TYPE, ElementType.CONSTRUCTOR})
public @interface WorkerThreadOnly {}
并且
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
@Target({ElementType.METHOD, ElementType.TYPE, ElementType.CONSTRUCTOR})
public @interface EventDispatchThreadOnly {}
之后,我定义了执行实际检查的Aspect:
import javax.swing.SwingUtilities;
public aspect ThreadChecking {
pointcut selection() : execution (* *(..));
pointcut edt() : selection() &&
(within (@EventDispatchThreadOnly *) ||
@annotation(EventDispatchThreadOnly));
pointcut worker() : selection() &&
(within (@WorkerThreadOnly *) ||
@annotation(WorkerThreadOnly));
before(): edt() {
assert (SwingUtilities.isEventDispatchThread());
}
before(): worker() {
assert (!SwingUtilities.isEventDispatchThread());
}
}
现在在应该线程限制的方法或类中添加@EventDispatchThreadOnly或@WorkerThreadOnly。不要在线程安全的方法中添加任何内容。
最后,只需启用断言(JVM选项-ea),您很快就会发现违规行为在哪里。
供参考,这是Mark所提到的
Alexander Potochkin的解决方案。它是一种类似的方法,但它检查您的应用程序对Swing方法的调用,而不是您的应用程序内部的调用。这两种方法是互补的,可以一起使用。
import javax.swing.*;
aspect EdtRuleChecker {
private boolean isStressChecking = true;
public pointcut anySwingMethods(JComponent c):
target(c) && call(* *(..));
public pointcut threadSafeMethods():
call(* repaint(..)) ||
call(* revalidate()) ||
call(* invalidate()) ||
call(* getListeners(..)) ||
call(* add*Listener(..)) ||
call(* remove*Listener(..));
before(JComponent c): anySwingMethods(c) &&
!threadSafeMethods() &&
!within(EdtRuleChecker) {
if(!SwingUtilities.isEventDispatchThread() &&
(isStressChecking || c.isShowing()))
{
System.err.println(thisJoinPoint.getSourceLocation());
System.err.println(thisJoinPoint.getSignature());
System.err.println();
}
}
before(): call(JComponent+.new(..)) {
if (isStressChecking && !SwingUtilities.isEventDispatchThread()) {
System.err.println(thisJoinPoint.getSourceLocation());
System.err.println(thisJoinPoint.getSignature() +
" *constructor*");
System.err.println();
}
}
}