5

Tôi đã tìm thấy nhiều hướng dẫn và ví dụ về cách sử dụng EDT một cách chính xác, tuy nhiên tôi muốn nghe như thế nào người ta nên đi theo cách khác xung quanh: kiểm tra ứng dụng phức tạp có giao diện Swing và nhiều chức năng liên quan đến hoạt động mạng dài và tìm nơi EDT được sử dụng không đúng cách.Cách kiểm tra ứng dụng Swing để sử dụng chính xác EDT (Event DIspatch Thread)

Tôi đã phát hiện ra rằng

SwingUtilities.isEventDispatchThread() 

có thể được sử dụng để kiểm tra xem một đoạn mã nằm bên trong EDT hay không, vì vậy tôi có thể kiểm tra xem tất cả các hoạt động dài không xảy ra được nơi bên trong nơi SwingUtilities .isEventDispatchThread() trả về true.

Có đúng không? có cái gì tốt hơn tôi có thể để trong một cách gỡ lỗi toàn bộ ứng dụng trong tìm kiếm sử dụng không chính xác của EDT? Cảm ơn bạn.

+3

Hãy xem tại địa chỉ: http://weblogs.java.net/blog/alexfromsun/archive/2006/02/debugging_swing.html – kiheru

+2

các chiến lược kiểm tra điển hình là theo chiều ngược lại: họ tìm những nơi mà bạn truy cập các thành phần Swing ngoài EDT (so với kiểm tra xem mã chạy dài có xảy ra trên EDT) hay không, không thể thêm mã vào vị trí mà bạn cho là dài hạn – kleopatra

+0

ANd như thế nào tìm nơi bạn truy cập các thành phần Swing ngoài EDT? – dendini

Trả lời

6

Có đúng không?

Có, kiểm tra giá trị SwingUtilities.isEventDispatchThread() là một cách để xem mã của bạn có nằm trên chuỗi sự kiện (EDT) hay không.

Một cách khác là hiển thị hoặc in Thread.currentThread().getName(). EDT hầu như luôn có tên "AWT-EventQueue-0".

Đoạn mã tiện lợi này xuất phát từ bài viết, Debugging Swing, the final summary. Tuy nhiên, nó không phải là một trình gỡ lỗi Swing hoàn chỉnh. Mã này chỉ kiểm tra các vi phạm tái phạm.

Bài viết liệt kê các phương pháp gỡ lỗi khác hoàn chỉnh hơn.

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

Tôi quan tâm nhiều hơn đến các kỹ thuật để xác minh EDT được sử dụng chính xác hơn là cách tìm kiếm nếu tôi ở trong hoặc ngoài EDT (cũng bởi vì isEventDispatchThread dường như thực hiện công việc của mình). Có người đề nghị làm theo cách khác vòng và "tìm những nơi mà bạn truy cập các thành phần Swing ra khỏi EDT" – dendini

2

Một cách kiểm tra việc sử dụng chính xác EDT của toàn bộ ứng dụng là sử dụng tác nhân java. Mã dưới đây là phiên bản cải tiến của Đại lý được đăng theo số Debugging Swing, the final Summary. Nó hoạt động với ASM 4.1. Tạo một Jar chứa asm-all-4.1.jar (unpacked), mã được biên dịch và một tệp kê khai chỉ rõ tác nhân là Premain-Class và bắt đầu.

/** 
* 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

Tôi mới đến đại lý java. Bạn có thể cung cấp hướng dẫn chi tiết hơn về cách sử dụng lớp Swing EDTCheckAgent trong một dự án hiện có không? – peterboston

+0

Tôi đã cập nhật câu trả lời. Nó đã mô tả cách đóng gói nó, bây giờ tôi đã thêm tùy chọn -javaagent: Nó có thể có ý nghĩa để tạo ra một dự án github cho nó. Bạn nghĩ sao? Bạn quan tâm đến việc đó? – ruediste

+0

Cảm ơn bạn đã cập nhật. Tôi đã thực sự quản lý để làm cho nó hoạt động với ứng dụng của tôi. Nhưng có vẻ như không thể tìm thấy bất cứ điều gì sai trái từ ứng dụng của tôi. Với RepaintManager, một số vi phạm được báo cáo và tôi đã kiểm tra kết quả là vi phạm. – peterboston