2015-09-22 2 views
4

Я ищу возможные причины, по которым EDT отключается и не перезапускается. Более конкретный, у меня есть набор тестов, из-за которого время от времени один из тестов страдает от тайм-аута. Свалка нити всегда очень похожа на следующее (где я раздел некоторые ненужные строки из основного потока):Что может привести к тому, что EDT не запустится?

Full thread dump Java HotSpot(TM) 64-Bit Server VM (24.79-b02 mixed mode): 

"Attach Listener" daemon prio=10 tid=0x00007f7c60001000 nid=0x5d0f runnable [0x0000000000000000] 
    java.lang.Thread.State: RUNNABLE 

"main-SharedResourceRunner" daemon prio=10 tid=0x00007f7c908e6000 nid=0x5ce6 in Object.wait() [0x00007f7c8416a000] 
    java.lang.Thread.State: WAITING (on object monitor) 
    at java.lang.Object.wait(Native Method) 
    - waiting on <0x00000000eed580f0> (a jogamp.opengl.SharedResourceRunner) 
    at java.lang.Object.wait(Object.java:503) 
    at jogamp.opengl.SharedResourceRunner.run(SharedResourceRunner.java:252) 
    - locked <0x00000000eed580f0> (a jogamp.opengl.SharedResourceRunner) 
    at java.lang.Thread.run(Thread.java:745) 

"AWT-XAWT" daemon prio=10 tid=0x00007f7c9085d000 nid=0x5ce3 runnable [0x00007f7c8456e000] 
    java.lang.Thread.State: RUNNABLE 
    at sun.awt.X11.XToolkit.waitForEvents(Native Method) 
    at sun.awt.X11.XToolkit.run(XToolkit.java:541) 
    at sun.awt.X11.XToolkit.run(XToolkit.java:505) 
    at java.lang.Thread.run(Thread.java:745) 

"Java2D Disposer" daemon prio=10 tid=0x00007f7c90840800 nid=0x5ce2 in Object.wait() [0x00007f7c8466f000] 
    java.lang.Thread.State: WAITING (on object monitor) 
    at java.lang.Object.wait(Native Method) 
    - waiting on <0x00000000eee2f878> (a java.lang.ref.ReferenceQueue$Lock) 
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:135) 
    - locked <0x00000000eee2f878> (a java.lang.ref.ReferenceQueue$Lock) 
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:151) 
    at sun.java2d.Disposer.run(Disposer.java:145) 
    at java.lang.Thread.run(Thread.java:745) 

"Service Thread" daemon prio=10 tid=0x00007f7c9009b800 nid=0x5cdc runnable [0x0000000000000000] 
    java.lang.Thread.State: RUNNABLE 

"C2 CompilerThread1" daemon prio=10 tid=0x00007f7c90099800 nid=0x5cdb waiting on condition [0x0000000000000000] 
    java.lang.Thread.State: RUNNABLE 

"C2 CompilerThread0" daemon prio=10 tid=0x00007f7c90096800 nid=0x5cda waiting on condition [0x0000000000000000] 
    java.lang.Thread.State: RUNNABLE 

"Signal Dispatcher" daemon prio=10 tid=0x00007f7c90094000 nid=0x5cd9 runnable [0x0000000000000000] 
    java.lang.Thread.State: RUNNABLE 

"Finalizer" daemon prio=10 tid=0x00007f7c90072000 nid=0x5cd8 in Object.wait() [0x00007f7c94e73000] 
    java.lang.Thread.State: WAITING (on object monitor) 
    at java.lang.Object.wait(Native Method) 
    - waiting on <0x00000000eee34650> (a java.lang.ref.ReferenceQueue$Lock) 
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:135) 
    - locked <0x00000000eee34650> (a java.lang.ref.ReferenceQueue$Lock) 
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:151) 
    at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209) 

"Reference Handler" daemon prio=10 tid=0x00007f7c90070000 nid=0x5cd7 in Object.wait() [0x00007f7c94f74000] 
    java.lang.Thread.State: WAITING (on object monitor) 
    at java.lang.Object.wait(Native Method) 
    - waiting on <0x00000000eedcc110> (a java.lang.ref.Reference$Lock) 
    at java.lang.Object.wait(Object.java:503) 
    at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:133) 
    - locked <0x00000000eedcc110> (a java.lang.ref.Reference$Lock) 

"main" prio=10 tid=0x00007f7c9000c000 nid=0x5cd1 in Object.wait() [0x00007f7c99c20000] 
    java.lang.Thread.State: WAITING (on object monitor) 
    at java.lang.Object.wait(Native Method) 
    - waiting on <0x00000000eb3adf98> (a java.awt.EventQueue$1AWTInvocationLock) 
    at java.lang.Object.wait(Object.java:503) 
    at java.awt.EventQueue.invokeAndWait(EventQueue.java:1282) 
    - locked <0x00000000eb3adf98> (a java.awt.EventQueue$1AWTInvocationLock) 
    at java.awt.EventQueue.invokeAndWait(EventQueue.java:1263) 


"VM Thread" prio=10 tid=0x00007f7c9006b800 nid=0x5cd6 runnable 

"GC task thread#0 (ParallelGC)" prio=10 tid=0x00007f7c90022000 nid=0x5cd2 runnable 

"GC task thread#1 (ParallelGC)" prio=10 tid=0x00007f7c90023800 nid=0x5cd3 runnable 

"GC task thread#2 (ParallelGC)" prio=10 tid=0x00007f7c90025800 nid=0x5cd4 runnable 

"GC task thread#3 (ParallelGC)" prio=10 tid=0x00007f7c90027800 nid=0x5cd5 runnable 

"VM Periodic Task Thread" prio=10 tid=0x00007f7c900ae800 nid=0x5cdd waiting on condition 

JNI global references: 297 

Обратите внимание, как main нити использует EventQueue.invokeAndWait планировать что-то на EDT, но нет EDT в дампе потока. И нет EDT означает, что поток main будет ждать вечно, потому что Runnable никогда не заканчивается.

В тот момент, когда был сделан сброс нити, на EDT было запланировано некоторое количество Runnable с, и все они прошли успешно, или тест не достигнет этой точки. Это говорит о том, что EDT разбился и не мог быть перезапущен.

К сожалению, у меня нет кода для воспроизведения проблемы. Я даже не могу воспроизвести это на своей собственной машине разработки с тестом, который иногда страдает от проблемы. Мне даже очень сложно воспроизвести это на CI, поскольку, похоже, тайм-аут только один раз в каждые несколько сотен пробегов.

Я ищу предложения, которые могут вызывать такое поведение, или что я могу сделать, чтобы исследовать это и стабилизировать мой тест. Мое предположение, что исключение вызвало EDT аварии, но даже тогда EDT должен восстановиться и просто быть в состоянии выполнить следующий Runnable отправил к нему, как показано в следующем коде:

import java.awt.EventQueue; 
import java.lang.reflect.InvocationTargetException; 


public class Test { 
    public static void main(String[] args) throws InvocationTargetException, InterruptedException { 
    try { 
     EventQueue.invokeAndWait(new Runnable() { 
     @Override 
     public void run() { 
      throw new RuntimeException("exception"); 
     } 
     }); 
    } catch (Exception e) { 
     //ignore 
    } 
    EventQueue.invokeAndWait(
     new Runnable() { 
      @Override 
      public void run() { 
      System.out.println("EDT restarted"); 
      } 
     } 
    ); 
    System.out.println("All runnables finished"); 
    } 
} 

отметить, что моя тест не имеет специального UncaughtExceptionHandler s, установленного на EDT или любой другой нити, и он не заменил значение по умолчанию UncaughtExceptionHandler. Я даже не уверен, было ли исключение в EDT. Система CI теряет выходные сигналы System.err и System.out, когда есть тайм-аут. У меня есть только дамп потока.


Редактировать

Как я боюсь, вопрос не 100% ясно. Мой тестовый код выглядит

@Test 
public void testSomethingWhichInteractsWithTheEDT(){ 
    doStuffOnMainThread(); 
    //do or check something on the EDT 
    EventQueue.invokeAndWait(new Runnable(){...}); 
    doMoreStuffOnMainThread(); 
    //do or check something else on the EDT 
    EventQueue.invokeAndWait(new Runnable(){...}); 
} 

и иногда, один из тех

EventQueue.invokeAndWait(new Runnable(){...}); 

вызовов на главном потоке будет блокировать до бесконечности, а поток дамп взят в тот момент больше не будет показывать экземпляр "AWT-EventQueue-0".

И хотя в тесте используются компоненты Swing, они никогда не становятся видимыми и не добавляются к компоненту верхнего уровня. Для простоты предположим, что я делаю JPanel, но никогда не добавляю его в JFrame.

Это означает, что:

  • Виртуальная машина Java остается живым независимой или нет EDT жив, до конца моего теста не будет достигнута. Это связано с тем, что основной поток работает до конца теста. Как только мой тестовый код закончится, JVM выйдет без использования каких-либо компонентов Swing, поскольку они никогда не были видимыми.
  • Разные Runnable s, которые я хочу выполнить на EDT, запланированы с использованием invokeAndWait. Между ними вполне возможно, что EDT отключается, так как нет видимых верхних компонентов и незавершенных событий, а следующий Runnable выполняется на «новом» EDT.

Но, насколько я могу судить, это не противоречит правилам параллелизма, связанным с Swing. Я планирую все операции над правильным потоком, и в правилах ничего не сказано о том, что вам нужно постоянно поддерживать компонент верхнего уровня во время выполнения вашей программы, чтобы поддерживать тот же EDT вживую. Тот факт, что EDT заменяется (что также может произойти из-за исключения as discussed here), должен AFAIK не блокировать последующие вызовы EventQueue#invokeAndWait.

+0

хорошо, но как, что, когда это Контейнер верхнего уровня хотя бы один раз (действительно) видимый ..., потому что без этого шага не тестируется каким-то образом, все – mKorbel

+0

@mKorbel Не совсем уверен, что вы имеете в виду, но в этом конкретном тесте у меня нет видимых компонентов верхнего уровня. У меня есть компоненты Swing, но я никогда не добавляю их в компонент верхнего уровня и не делаю их видимыми. – Robin

+0

@mKorbel. Я попытался выяснить вопрос, так как я все еще не уверен на 100%, как ваш ответ связан с моим вопросом. – Robin

ответ

2

@mKorbel Не совсем уверен, что вы имеете в виду, но в этом конкретном тесте у меня нет видимых компонентов верхнего уровня. У меня есть компоненты качаться, но никогда не поместить их в компонент верхнего уровня и я не сделать их видимыми

@Robin

  • то не представляется возможным проверить EDT
  • invokeAndWait должны быть всегда проверены для EventQueue.isDispatchThread/SwingUtilities.isEventDispatchThread, чтобы избежать исключения из RepaintManager
  • довольно, я немного удивлен этим вопросом (не flamewar пожалуйста :-)

, например

import java.awt.EventQueue; 
import java.awt.TextField; 
import java.text.SimpleDateFormat; 
import java.util.Date; 
import java.util.concurrent.*; 
import javax.swing.*; 

public class IsThereEDT { 

    private ScheduledExecutorService scheduler; 
    private AccurateScheduledRunnable periodic; 
    private ScheduledFuture<?> periodicMonitor; 
    private int taskPeriod = 30; 
    private SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss"); 
    private Date dateRun; 

    public IsThereEDT() { 
     scheduler = Executors.newSingleThreadScheduledExecutor(); 
     periodic = new AccurateScheduledRunnable() { 

      private final int ALLOWED_TARDINESS = 200; 
      private int countRun = 0; 
      private int countCalled = 0; 

      @Override 
      public void run() { 
       countCalled++; 
       if (this.getExecutionTime() < ALLOWED_TARDINESS) { 
        countRun++; 
        isThereReallyEDT(); // non on EDT 
       } 
      } 
     }; 
     periodicMonitor = scheduler.scheduleAtFixedRate(periodic, 0, taskPeriod, TimeUnit.SECONDS); 
     periodic.setThreadMonitor(periodicMonitor); 
     isThereReallyEDT(); 
     //TextField text = new TextField(); 
     //JFrame frame1 = new JFrame("Frame 1"); 
     /*SwingUtilities.invokeLater(new Runnable() { 

      @Override 
      public void run() {     
       isThereReallyEDT(); 
       JFrame frame1 = new JFrame("Frame 1"); 
       frame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       frame1.getContentPane().add(new JLabel("Hello in frame 1")); 
       frame1.pack(); 
       frame1.setLocation(100, 100); 
       frame1.setVisible(true); 
      } 
     });*/ 
     /*SwingUtilities.invokeLater(new Runnable() { 

      @Override 
      public void run() { 
       JFrame frame2 = new JFrame("Frame 2"); 
       frame2.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       frame2.getContentPane().add(new JLabel("Hello in frame 2")); 
       frame2.pack(); 
       frame2.setLocation(200, 200); 
       frame2.setVisible(true); 
       isThereReallyEDT(); 
      } 
     });*/ 
     isThereReallyEDT(); 
    } 

    private void isThereReallyEDT() { 
     dateRun = new java.util.Date(); 
     System.out.println("       Time at : " + sdf.format(dateRun)); 
     if (EventQueue.isDispatchThread()) { 
      System.out.println("Calling from EventQueue.isDispatchThread"); 
     } else { 
      System.out.println("There isn't Live EventQueue.isDispatchThread, why any reason for that "); 
     } 
     if (SwingUtilities.isEventDispatchThread()) { 
      System.out.println("Calling from SwingUtilities.isEventDispatchThread"); 
     } else { 
      System.out.println("There isn't Live SwingUtilities.isEventDispatchThread, why any reason for that "); 
     } 
     System.out.println(); 
    } 

    public static void main(String[] args) { 
      IsThereEDT isdt = new IsThereEDT(); 
     /*SwingUtilities.invokeLater(new Runnable() { 

      @Override 
      public void run() { 
       JFrame frame = new JFrame(); 
       frame.setVisible(true); 
       try { 
        Thread.sleep(1000); 
       } catch (Exception e) { 
       } 
       frame.dispose(); 
       JOptionPane.showMessageDialog(frame, "Test case 1, " 
         + "JVM won't terminate."); 
      } 
     });*/ 
    } 
} 

abstract class AccurateScheduledRunnable implements Runnable { 

    private ScheduledFuture<?> thisThreadsMonitor; 

    public void setThreadMonitor(ScheduledFuture<?> monitor) { 
     this.thisThreadsMonitor = monitor; 
    } 

    protected long getExecutionTime() { 
     long delay = -1 * thisThreadsMonitor.getDelay(TimeUnit.MILLISECONDS); 
     return delay; 
    } 
} 

с правильным и хорошим выходом (без показа верхнего уровня контейнера по крайней мере один раз (на самом деле), видимый на экран)

   Time at : 11:03:50 There isn't Live EventQueue.isDispatchThread, why any reason for that There isn't Live SwingUtilities.isEventDispatchThread, why any reason for that 

      Time at : 11:04:20 There isn't Live EventQueue.isDispatchThread, why any reason for that There isn't Live SwingUtilities.isEventDispatchThread, why any reason for that 

      Time at : 11:04:50 There isn't Live EventQueue.isDispatchThread, why any reason for that There isn't Live SwingUtilities.isEventDispatchThread, why any reason for that 
+0

Не совсем уверен, что Я понимаю этот ответ. Ваш код, который запускается как есть, будет, конечно, выводить, что он не находится на EDT. Почему? И, конечно, если я раскомментирую все, кадр останется видимым, и JVM не выйдет. Моя проблема в том, что я вызываю 'EventQueue.invokeAndWait' из основного потока и что он просто застрял там, потому что он каким-то образом не может запустить EDT. И, на мой взгляд, это не имеет ничего общего с видимыми или невидимыми компонентами верхнего уровня, потому что для того, чтобы сделать первый компонент верхнего уровня видимым, мне пришлось бы делать точно такой же вызов. – Robin

+0

@Robin AFAIK EventDispatchThread можно запустить, завершить, затем тестируются вместе с некоторыми JComponent, которые должны быть видимыми, эти правила реализованы в API AWT/Swing, простой JFrame.setVisible (true), начиная с EDT, что невозможно логически завершить (GC, anything == missing finalize()) iuntill текущий экземпляр JVM жив, существует много лагов об использовании SwingWorker, который используется без видимого JComponent, в противном случае вы можете запустить EDT грязным взломом, уделив этому правилу, чтобы переопределить isVisible для контейнера верхнего уровня, m никогда не видел стабильного кода тестирования для – mKorbel

+0

Я понимаю, что вам нужен видимый компонент верхнего уровня, чтобы сохранить EDT в живых. Но мне все равно, что он жив или нет. Я просто хочу, чтобы иметь возможность вызывать 'EventQueue.invokeAndWait' из другого потока, чтобы запустить что-то в EDT.Это должно поддерживаться, или вы никогда не сможете сделать свой первый компонент верхнего уровня видимым. В моем тесте JVM остается в живых, потому что мой основной поток все еще работает, поэтому не нужно, чтобы EDT поддерживал мою JVM. Я просто хочу запустить определенные части теста на EDT, потому что они взаимодействуют с невидимыми компонентами Swing. Я все еще не понимаю, что я делаю неправильно. – Robin

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