5

Я нашел много руководств и примеров по правильному использованию EDT, однако мне хотелось бы услышать, как нужно идти в обратном направлении: проверьте сложное приложение с графическим интерфейсом Swing и многими функциями, включающими длительные сетевые операции и поиск неправильного использования EDT.Как проверить приложение Swing для правильного использования EDT (Event DIspatch Thread)

Я обнаружил, что

SwingUtilities.isEventDispatchThread() 

может быть использован для проверки один кусок кода внутри EDT или нет, так что я мог проверить, что все длинные операции не случается внутри места, где SwingUtilities .isEventDispatchThread() возвращает true.

Правильно ли это? есть ли что-то лучшее, что я мог, чтобы отладить все приложение в поисках неправильного использования EDT? Спасибо.

+3

Взгляните: http://weblogs.java.net/blog/alexfromsun/archive/2006/02/debugging_swing.html – kiheru

+2

типичные стратегии проверочные являются наоборот: они находят места, где вы получить доступ к компонентам Swing с EDT (по сравнению с проверкой того, не выполняется ли длительный код на EDT) - логично, последнее невозможно без добавления кода в том месте, которое, как вы подозреваете, будет длительным – kleopatra

+0

И как один найти места, где вы получаете доступ к компонентам Swing с EDT? – dendini

ответ

6

Правильно ли это?

Да, проверка значения SwingUtilities.isEventDispatchThread() - это один из способов узнать, находится ли ваш код в потоке отправки событий (EDT) или нет.

Другой способ - отобразить или распечатать Thread.currentThread().getName(). EDT почти всегда имеет имя «AWT-EventQueue-0».

Эта замечательная часть кода взята из статьи, Debugging Swing, the final summary. Однако это не полный отладчик Swing. Этот код проверяет только переписку.

В статье перечислены другие методы отладки, которые являются более полными.

import javax.swing.JComponent; 
import javax.swing.RepaintManager; 
import javax.swing.SwingUtilities; 

public class CheckThreadViolationRepaintManager extends RepaintManager { 
    // it is recommended to pass the complete check 
    private boolean completeCheck = true; 

    public boolean isCompleteCheck() { 
     return completeCheck; 
    } 

    public void setCompleteCheck(boolean completeCheck) { 
     this.completeCheck = completeCheck; 
    } 

    public synchronized void addInvalidComponent(JComponent component) { 
     checkThreadViolations(component); 
     super.addInvalidComponent(component); 
    } 

    public void addDirtyRegion(JComponent component, int x, int y, int w, int h) { 
     checkThreadViolations(component); 
     super.addDirtyRegion(component, x, y, w, h); 
    } 

    private void checkThreadViolations(JComponent c) { 
     if (!SwingUtilities.isEventDispatchThread() 
       && (completeCheck || c.isShowing())) { 
      Exception exception = new Exception(); 
      boolean repaint = false; 
      boolean fromSwing = false; 
      StackTraceElement[] stackTrace = exception.getStackTrace(); 
      for (StackTraceElement st : stackTrace) { 
       if (repaint && st.getClassName().startsWith("javax.swing.")) { 
        fromSwing = true; 
       } 
       if ("repaint".equals(st.getMethodName())) { 
        repaint = true; 
       } 
      } 
      if (repaint && !fromSwing) { 
       // no problems here, since repaint() is thread safe 
       return; 
      } 
      exception.printStackTrace(); 
     } 
    } 
} 
+0

Меня больше интересуют методы проверки правильности EDT, чем способы поиска, если я внутри или вне EDT (также потому, что isEventDispatchThread, похоже, выполняет свою работу). Кто-то предложил сделать наоборот и «найти места, где вы получаете доступ к компонентам Swing с EDT» – dendini

2

Одним из способов проверки правильного использования EDT всего приложения является использование java-агента. Нижеприведенный код является улучшенной версией Агента, размещенной под Debugging Swing, the final Summary. Он работает с ASM 4.1. Создайте Jar, содержащий asm-all-4.1.jar (распакованный), скомпилированный код и манифест, указывающий агента как Premain-Class и продолжайте работу.

/** 
* A java agent which transforms the Swing Component classes in such a way that a stack 
* trace will be dumped or an exception will be thrown when they are accessed from a wrong thread. 
* 
* To use it, add 
* <pre> 
* -javaagent:${workspace_loc:MyProject/tool/util/swingEDTCheck}/swingEDTCheck.jar 
* </pre> 
* 
* to the VM arguments of a run configuration. This will cause the stack traces to be dumped. 
* 
* Use 
* <pre> 
* -javaagent:${workspace_loc:MyProject/tool/util/swingEDTCheck}/swingEDTCheck.jar=throw 
* </pre> 
* to throw exceptions. 
* 
*/ 
public class SwingEDTCheckAgent { 

    public static void premain(String args, Instrumentation inst) { 
     boolean throwing = false; 
     if ("throw".equals(args)) { 
      throwing = true; 
     } 
     inst.addTransformer(new Transformer(throwing)); 
    } 

    private static class Transformer implements ClassFileTransformer { 

     private final boolean throwing; 

     public Transformer(boolean throwing) { 
      this.throwing = throwing; 
     } 

     @Override 
     public byte[] transform(ClassLoader loader, 
      String className, 
      Class classBeingRedefined, 
      ProtectionDomain protectionDomain, 
      byte[] classfileBuffer) 
      throws IllegalClassFormatException { 
      // Process all classes in javax.swing package which names start with J 
      if (className.startsWith("javax/swing/J")) { 
       ClassReader cr = new ClassReader(classfileBuffer); 
       ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_FRAMES); 
       ClassVisitor cv = new EdtCheckerClassAdapter(cw, throwing); 
       cr.accept(cv, 0); 
       return cw.toByteArray(); 
      } 
      return classfileBuffer; 
     } 
    } 

    private static class EdtCheckerClassAdapter extends ClassVisitor { 

     private final boolean throwing; 

     public EdtCheckerClassAdapter(ClassVisitor classVisitor, boolean throwing) { 
      super(Opcodes.ASM4, classVisitor); 
      this.throwing = throwing; 
     } 

     @Override 
     public MethodVisitor visitMethod(final int access, 
      final String name, 
      final String desc, 
      final String signature, 
      final String[] exceptions) { 
      MethodVisitor mv = 
       cv.visitMethod(access, name, desc, signature, exceptions); 

      if (name.startsWith("set") || name.startsWith("get") || name.startsWith("is")) { 
       return new EdtCheckerMethodAdapter(mv, throwing); 
      } else { 
       return mv; 
      } 
     } 
    } 

    private static class EdtCheckerMethodAdapter extends MethodVisitor { 

     private final boolean throwing; 

     public EdtCheckerMethodAdapter(MethodVisitor methodVisitor, boolean throwing) { 
      super(Opcodes.ASM4, methodVisitor); 
      this.throwing = throwing; 
     } 

     @Override 
     public void visitCode() { 
      mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/awt/EventQueue", "isDispatchThread", "()Z"); 
      Label l1 = new Label(); 
      mv.visitJumpInsn(Opcodes.IFNE, l1); 
      Label l2 = new Label(); 
      mv.visitLabel(l2); 

      if (throwing) { 
       // more Aggressive: throw exception 
       mv.visitTypeInsn(Opcodes.NEW, "java/lang/RuntimeException"); 
       mv.visitInsn(Opcodes.DUP); 
       mv.visitLdcInsn("Swing Component called from outside the EDT"); 
       mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/RuntimeException", "<init>", "(Ljava/lang/String;)V"); 
       mv.visitInsn(Opcodes.ATHROW); 

      } else { 
       // this just dumps the Stack Trace 
       mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Thread", "dumpStack", "()V"); 
      } 
      mv.visitLabel(l1); 
     } 
    } 
} 
+0

Я новичок в java-агенте. Можете ли вы дать более подробную инструкцию о том, как использовать класс Swing EDTCheckAgent в существующем проекте? – peterboston

+0

Я обновил ответ. Он уже описывает, как его упаковать, теперь я добавил параметр -javaagent:. Возможно, имеет смысл создать для него проект github. Как вы думаете? Заинтересованы в этом? – ruediste

+0

Спасибо за ваше обновление. Мне действительно удалось заставить его работать с моим приложением. Но, похоже, он не может найти ничего плохого в моем приложении. С RepaintManager сообщается о нескольких нарушениях, и я проверял, что результаты являются нарушениями. – peterboston

Смежные вопросы