Я ищу возможные причины, по которым 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
.
хорошо, но как, что, когда это Контейнер верхнего уровня хотя бы один раз (действительно) видимый ..., потому что без этого шага не тестируется каким-то образом, все – mKorbel
@mKorbel Не совсем уверен, что вы имеете в виду, но в этом конкретном тесте у меня нет видимых компонентов верхнего уровня. У меня есть компоненты Swing, но я никогда не добавляю их в компонент верхнего уровня и не делаю их видимыми. – Robin
@mKorbel. Я попытался выяснить вопрос, так как я все еще не уверен на 100%, как ваш ответ связан с моим вопросом. – Robin