我正在查找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意味着main
線程將永遠等待,因爲Runnable
永遠不會終止。
在執行線程轉儲的時刻,EDT上已經安排了一些Runnable
,並且這些都已成功運行或者測試不會達到此點。這表明美國東部時間墜毀,無法重新啓動。
不幸的是,我沒有任何代碼來重現問題。我甚至無法在我自己的開發機器上重現這個問題,有時候這種測試會遇到問題。我甚至很難在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");
}
}
注意,我測試沒有在EDT或任何其他線程上設置特殊的UncaughtExceptionHandler
,也沒有替換默認的UncaughtExceptionHandler
。我甚至不確定美國東部時間有沒有例外。出現超時時,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
。
這意味着:
- 的JVM仍然活着獨立於美國東部時間是否是活的,直到達到我的測試結束。這是因爲主線程正在運行直到測試結束。一旦我的測試代碼結束,JVM將退出,而不必處理任何這些Swing組件,因爲它們從未顯示。
- 我想在
EDT
上執行的不同Runnable
使用invokeAndWait
進行計劃。在兩者之間,由於沒有可見的頂部組件並且沒有未決事件,所以EDT關閉是完全可能的,並且下一個Runnable
在「新」EDT上執行。
但據我所知,這不是針對任何Swing相關的併發規則。我將所有操作安排在正確的線程上,並且規則中沒有提到您需要在程序運行期間隨時保持頂級組件可見,以保持相同的EDT存活。如果EDT被替換(這也可能由於例外as discussed here)而發生,則AFAIK不應阻止任何後續的EventQueue#invokeAndWait
調用。
不錯,但怎麼樣,這是當頂級容器至少有一次(真的)可見......,因爲沒有這個步驟是不可測試的,所有的東西 – mKorbel
@mKorbel不太確定你的意思,但在特定的測試中,我沒有可見的頂級組件。我有Swing組件,但是從來沒有把它們放在頂層組件中,也不讓它們可見 – Robin
@mKorbel我試着澄清這個問題,因爲我仍然不能100%確定你的答案與我的問題有關 – Robin