2013-04-04 11 views
6

Ich habe gerade eingeschaltet von Oracle JDK 1.6, JDK 1.7.0_03 zu öffnen, und ich habe eine ziemlich bemerkenswerte Deadlock auf Ausfahrt getroffen:System.exit ist unter Linux nicht Thread-sicher?

java.lang.Thread.State: WAITING (on object monitor) 
at java.lang.Object.wait(Native Method) 
at java.lang.Thread.join(Thread.java:1258) 
- locked <0x8608dda0> (a sun.awt.X11.XToolkit$1$1) 
at java.lang.Thread.join(Thread.java:1332) 
at java.lang.ApplicationShutdownHooks.runHooks(ApplicationShutdownHooks.java:106) 
at java.lang.ApplicationShutdownHooks$1.run(ApplicationShutdownHooks.java:46) 
at java.lang.Shutdown.runHooks(Shutdown.java:123) 
at java.lang.Shutdown.sequence(Shutdown.java:167) 
at java.lang.Shutdown.exit(Shutdown.java:212) 
- locked <0x8603df28> (a java.lang.Class for java.lang.Shutdown) 
at java.lang.Runtime.exit(Runtime.java:107) 
at java.lang.System.exit(System.java:960) 

Es scheint, dass Sie System.exit aus der AWT nennen müssen Ereigniswarteschlange Ist das echt? Es gibt keine Dokumentation eines Threads Bedarf in den Sun docs Runtime.exit

ich andere überraschende Fälle getroffen haben, wo immer die AWT Baumsperre nur auf Linux erforderlich ist, aber dieses nimmt den Kuchen. Ist das ein Fehler oder habe ich gerade etwas in der Dokumentation verpasst?

+2

eine SSCCE erhielt (http://sscce.org/) demonstriert die Sackgasse? – NPE

+0

Die 'System.exit'-Methode erzwingt die Beendigung aller Threads in der Java Virtual Machine. Sie beheben das erwähnte Deadlock-Problem nicht, indem Sie System.exit verwenden, Sie beenden das Programm, bevor der Deadlock auftritt. Wenn Sie normal aufhören, werden Ihre anderen Threads ohne die Unterstützung des Hauptthreads fortgesetzt und anscheinend können sie es ohne es nicht tun. –

Antwort

1

Es hängt davon ab, ob die Methode runHooks alle durch Runtime.addShutdownHook registrierten Hook-Threads startet und darauf wartet, dass sie beendet werden. Wenn einer Ihrer Hook-Threads Ressourcen sperrt, die der AWT-Ereignisthread ebenfalls benötigt, können sie zu einer Dead-Sperre führen.

Wenn Sie System.exit in Ihrem AWT Event Thread zu nennen haben, schlage ich vor, Sie es in einem anderen Thread nennen wie:

new Thread(){ 
      public void run() { 
       System.exit(0); 
      } 
    }.start(); 
+0

Ich liebe diesen Ausschnitt. Es ist wirklich eine Sache von Schönheit. Vielen Dank. –

1

Es ist unmöglich zu sagen, ob dies ein Fehler in der Laufzeit ist, ohne zu wissen mehr darüber, was die Anwendung tut (idealerweise würde dies die Form einer SSCCE annehmen).

Zum Beispiel zeigt das folgende Beispiel einen ähnlichen Deadlock mit System.exit(). Es ist jedoch eindeutig ein Fehler in der Anwendung, nicht in System.exit():

public class OhNo { 

    final static Object lock = new Object(); 

    public static void main(String[] args) { 
     new Thread(new Runnable() { 
      public void run() { 
       synchronized (lock) { 
        for (;;) { 
        } 
       } 
      } 
     }).start(); 
     Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { 
      public void run() { 
       synchronized (lock) { 
        System.out.println("in shutdown hook"); 
       } 
      } 
     })); 
     System.out.println("about to call System.exit()"); 
     System.exit(0); 
    } 
} 
+0

AWT-EventQueue-0 ruft mich an, und ich nehme eine Sperre für ein Objekt O. O ist beschäftigt, so dass die AWT-EventQueue-0 blockiert ist. O ruft System.exit() auf, und unter Linux wartet es auf die AWT-Baumsperre, die natürlich auf O wartet. Daher Deadlock. Wie auch immer, ich schätze, da es diese Shutdown-Hooks gibt, die seltsame Dinge tun könnten, ist die richtige Antwort, einen neuen Thread zum Herunterfahren zu erstellen, wie von Spring.Rush vorgeschlagen. Das scheint sehr robust zu sein. –