2015-09-22 33 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意味着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.errSystem.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調用。

+0

不錯,但怎麼樣,這是當頂級容器至少有一次(真的)可見......,因爲沒有這個步驟是不可測試的,所有的東西 – mKorbel

+0

@mKorbel不太確定你的意思,但在特定的測試中,我沒有可見的頂級組件。我有Swing組件,但是從來沒有把它們放在頂層組件中,也不讓它們可見 – Robin

+0

@mKorbel我試着澄清這個問題,因爲我仍然不能100%確定你的答案與我的問題有關 – Robin

回答

2

@mKorbel不太確定你的意思,但在特定的測試中,我沒有可見的頂級組件。我有Swing組件,但從來沒有把它們放在一個頂級組件我也不讓他們看到

@Robin

  • 那麼是不是可以測試EDT
  • invokeAndWait應始終測試爲EventQueue.isDispatchThread/SwingUtilities.isEventDispatchThreadRepaintManager
  • 相當避免例外,我對這個問題(先是有點不是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一起進行測試,這些JComponent必須是可見的,這些Rulles在AWT/Swing APIs中實現,簡單的JFrame.setVisible(true)從EDT開始,這是不可能在邏輯上終止的(GC,nothing == missing finalize() )直到當前的JVM實例還活着,有很多關於使用SwingWorker的滯後,這是使用沒有可見的JComponent,否則你可以通過骯髒的黑客啓動EDT,通過braeking這個rulles,覆蓋頂級容器isVisible,請注意我'米永遠不會看到穩定的測試代碼 – mKorbel

+0

我知道你需要一個可見的頂級組件來保持美國東部時間。但我不在乎它是否還活着。我只是想從另一個線程調用'EventQueue.invokeAndWait'來在EDT上運行一些東西。這應該被支持,否則你永遠無法看到你的第一個頂層組件。在我的測試中,JVM保持運行狀態,因爲我的主線程仍在運行,所以EDT不需要讓JVM保持活動狀態。我只想在EDT上運行測試的某些部分,因爲它們與不可見的Swing組件交互。我仍然沒有看到我做錯了什麼。 – Robin

相關問題