I am looking for possible causes for the EDT to shut down and not restart. More concrete, I have a test suite where occasionally one of the tests suffers from a time-out. The thread dump is always very similar to the following (where I stripped out some irrelevant lines from the main thread):
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
Note how the main
thread uses EventQueue.invokeAndWait
to schedule something on the EDT, but there is no EDT in the thread dump. And no EDT means the main
thread will wait forever because that Runnable
never terminates.
At the moment where the thread dump was taken, there were already some Runnable
s scheduled on the EDT, and those all ran successfully or the test wouldn't have reached this point. This suggests the EDT crashed, and could not be restarted.
Unfortunately, I have no code to reproduce the issue with. I cannot even reproduce this on my own development machine with the test that sometimes suffers from the issue. I even have a very hard time reproducing this on the CI, as it seems to time-out only once in every few hundred runs.
I am looking for suggestions what might be causing this behaviour, or what I can do to investigate this and stabilize my test. My best guess is that an exception caused the EDT to crash, but even then the EDT should recover and just be able to run the next Runnable
posted to it, as illustrated in the following code:
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");
}
}
Note that my test has no special UncaughtExceptionHandler
s set on the EDT or on any other thread, nor had it replaced the default UncaughtExceptionHandler
. I am not even sure whether there was an exception on the EDT. The CI system looses the System.err
and System.out
output when there is a time-out. I only have the thread dump available.
Edit
As I am afraid the question is not 100% clear. My test code looks like
@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(){...});
}
and occasionally, one of those
EventQueue.invokeAndWait( new Runnable(){...});
calls on the main thread would block indefinitely, and the thread dump taken at that point would no longer show the "AWT-EventQueue-0"
instance.
And although the test uses Swing components, they are never made visible nor are they added to a top-level component. For simplicity sake, assume I make a JPanel
but never add it to a JFrame
.
This means that:
- The JVM remains alive independent whether or not the EDT is alive, until the end of my test is reached. This is because the main thread is running until the end of the test. Once my test code ends, the JVM will exit without having to dispose any of those Swing components since they were never made visible.
- The different
Runnable
s that I want to execute on theEDT
are scheduled usinginvokeAndWait
. In between, it is perfectly possible that the EDT shuts down as there are no visible top components and no pending events, and that the nextRunnable
is executed on a "new" EDT.
But as far as I can tell, this is not against any Swing related concurrency rules. I schedule all operations on the correct thread, and there is nothing mentioned in the rules that you need to keep a top-level component visible at all times during the run of your program in order to keep the same EDT alive. The fact that the EDT gets replaced (which can also happen due to an exception as discussed here) should AFAIK not block any subsequent EventQueue#invokeAndWait
calls.