2016-08-02 8 views
5

Napisałem tak.Co uniemożliwia program?

public static void main(String[] args){ 
    Thread thread = new Thread(() -> { 
     while(true){ 
      try{ 
       // do something 
       Thread.sleep(10); 
      }catch(InterruptedException ex){ 
       System.out.println("ABC"); 
       break; 
      } 
     } 
    }); 
    JFrame frame = new JFrame(); 
    frame.setSize(1280,720); 
    frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 
    frame.addWindowListener(new WindowAdapter(){ 
     @Override 
     public void windowClosed(WindowEvent e){ 
      thread.interrupt(); 
     } 
    }); 
    thread.start(); 
    frame.setVisible(true); 
} 

Kiedy kliknąłem przycisk „Zamknij” w oknie,
program trwało kilka sekund do końca.
Co uniemożliwia programowi wyjście?
A jak mogę zamknąć program natychmiast bez przy użyciu JFrame.EXIT_ON_CLOSE?

Myślę, że mój wątek (while(true) wątek) kończy się natychmiast
ponieważ "ABC" jest wyświetlany wkrótce po kliknięciu przycisku "zamknij".

Dziękuję.

EDYTUJ

to samo wydarzyło się bez mojego wątku.

public static void main(String[] args){ 
    JFrame frame = new JFrame(); 
    frame.setSize(1280,720); 
    frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 
    frame.setVisible(true); 
} 

EDIT2

public static void main(String[] args){ 
    Runtime.getRuntime().addShutdownHook(new Thread(() -> { 
     Thread[] threads = new Thread[5]; 
     Thread.enumerate(threads); 
     System.out.println(Arrays.toString(threads)); 
     System.err.println(LocalDateTime.now() + " SHUTDOWN"); 
    } 
    )); 
    JFrame frame = new JFrame(); 
    frame.setSize(1280,720); 
    frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 
    frame.addWindowListener(new WindowAdapter(){ 
      @Override 
      public void windowClosed(WindowEvent e){ 
       Thread[] threads = new Thread[5]; 
       Thread.enumerate(threads); 
       System.out.println(Arrays.toString(threads)); 
       System.err.println(LocalDateTime.now() + " CLOSE"); 
      } 
     }); 
    frame.setVisible(true); 
} 

wyjście było:

[Thread[AWT-EventQueue-0,6,main], Thread[DestroyJavaVM,5,main], null, null, null] 
2016-08-02T19:04:50.465 CLOSE 
[Thread[DestroyJavaVM,5,main], Thread[Thread-0,5,main], null, null, null] 
2016-08-02T19:04:51.762 SHUTDOWN 
+0

Czy Twój pełny kod? Ponieważ 'thread' musi zostać zainicjowany – Cir0X

+0

Nie mogę tego odtworzyć. Po naprawieniu problemów z kompilacją, "ABC" jest natychmiast drukowane po kliknięciu przycisku zamykania, a program zostaje zakończony. Zapoznaj się także z http://stackoverflow.com/documentation/swing/2266/swing-hello-world#t=201608020924423960976, aby dowiedzieć się, jak poprawnie uruchomić aplikację Swing. –

+0

@ Cir0X Przepraszam, kod został uporządkowany dla jasności, redagowałem. –

Odpowiedz

0

Aby zakończyć swój program od razu można używać System.exit(0).

tak:

public static void main(String[] args){ 
    Thread thread = new Thread(() -> { 
     while(true){ 
      try{ 
       // do something 
       Thread.sleep(10); 
      }catch(InterruptedException ex){ 
       System.out.println("ABC"); 
       System.exit(0); 
      } 
     } 
    }); 
    JFrame frame = new JFrame(); 
    frame.setSize(1280,720); 
    frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 
    frame.addWindowListener(new WindowAdapter(){ 
     @Override 
     public void windowClosed(WindowEvent e){ 
      thread.interrupt(); 
     } 
    }); 
    thread.start(); 
    frame.setVisible(true); 
} 
+0

Przepraszam, nie chcę używać 'System.exit (0)', ponieważ chcę zakończyć program z moim wątkiem odpowiednio zakończonym. –

+2

To jest bardzo prymitywne i sprawia, że ​​użycie 'DISPOSE_ON_CLOSE' jest bezużyteczne. – ArcticLord

+0

@Shu S 'System.exit (0)' nie wygląda [to] (http://stackoverflow.com/a/7082054/3014979) źle w Swing – Cir0X

6

Podczas System.exit() powinny być powszechnie stosowane ze starannością, jednak Swing documentation wyraźnie stwierdza, że ​​jest to właściwe podejście w scenariuszach, jak pokazano na pytanie:

Kiedy ostatnie wyświetlane okno w wirtualnej maszynie Java (VM) zostaje usunięte, maszyna wirtualna może zostać zakończona. Zauważ jednak, że może być opóźnienie, zanim program zakończy się automatycznie i że pod pewnymi warunkami program może nadal działać. Jest to szybsze i bardziej bezpieczne zamknięcie programu przy użyciu System.exit(int).

Poniższy przykład nie pokazuje opóźnienia między operacją zamknięcia a hakiem zamykającym. Podczas usuwania połączenia System.exit(0) opóźnienie wynosi ok. można zaobserwować 1,3 sekundy:

package com.example.swing; 

import java.awt.event.WindowAdapter; 
import java.awt.event.WindowEvent; 
import java.time.LocalDateTime; 

import javax.swing.JFrame; 
import javax.swing.SwingUtilities; 

public class ExitDelay { 
    public static void main(String[] args){ 

     Runtime.getRuntime().addShutdownHook(new Thread(() -> System.err.println(LocalDateTime.now() + " SHUTDOWN"))); 

     SwingUtilities.invokeLater(() -> { 

      JFrame frame = new JFrame(); 
      frame.setSize(1280,720); 
      frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 
      frame.addWindowListener(new WindowAdapter(){ 
       @Override 
       public void windowClosed(WindowEvent e){ 
        System.err.println(LocalDateTime.now() + " CLOSE"); 

        // Do all required cleanup stuff. 
        // check that threads are done, close files, commit transactions etc. 
        // ... 

        System.exit(0); 
       } 
      }); 
      frame.setVisible(true); 

     }); 
    } 
} 
0

użyć DISPOSE_ON_CLOSE i to ma sens, ponieważ EXIT_ON_CLOSE użyłby System.exit aby zamknąć proces JVM ze wszystkich aktywnych wątków. A JFrame to złożona struktura, która wykorzystuje niektóre połączenia natywne do rejestrowania wywołań zwrotnych dla zdarzeń myszy w systemie operacyjnym. Więc czyste wyjście zajmuje trochę czasu. Dodatkowo Garbage Collector potrzebuje trochę czasu, aby wykryć, że AWT-Thread, który uruchamia JFrame, jest całkowicie zakończony oczyszczeniem, zanim go zabije. Uważam, że dopuszczalne jest 1,3 sekundy dla czystego wykończenia twojej aplikacji.
Ale jeśli naprawdę chcesz to zrobić, możesz wymusić koniec na innym Thread, który po prostu sprawdza w sposób ciągły, czy wszystkie działające wątki zakończyły pracę, a wszystkie JFrames zniknęły. A jeśli tak, to nazywa wielkie zło System.exit.


final JFrame frame = new JFrame(); // make your JFrame final 
final Thread thread = new Thread(() ... // make your Thread final 

i dodaj sprawdzanie koniec gwintu

final Thread endChecker = new Thread(() -> {    
    while(true){ 
     try{ 
      Thread.sleep(100); 
      if(!frame.isDisplayable() && !thread.isAlive()) 
       System.exit(0);     
     }catch(InterruptedException ex){ 
      break; 
     } 
    }   
}); 
endChecker.start(); 
+0

Dziękuję. Wątek endChecker to jedno rozwiązanie. –

Powiązane problemy