2013-07-22 10 views
7

Ho un'applicazione con una catena Try/Catch/Finally ben definita che esce ed esegue il blocco finally in condizioni normali, ma quando qualcuno premia prematuramente la X rossa nella GUI, il programma esiste completamente (codice = 0) e il blocco finale del thread principale non viene chiamato.Uscire un'applicazione con garbo?

Infatti, voglio che il programma esca con un clic del rosso-X, ma quello che non voglio è un salto del blocco finale {}! I sorta di messo nella parte più importante del blocco finally manualmente nella GUI, ma davvero non voglio farlo in questo modo perché voglio la GUI disaccoppiato dal programma vero e proprio:

class GUI { // ... 
... 
mainFrame.addWindowListener(new WindowAdapter() { 
    public void windowClosing(WindowEvent evt) { 
    try { 
     processObject.getIndicatorFileStream().close(); 
    } catch (Exception ignore) {} 
    System.exit(0); 
    } 
}); 
... 
} 

ma mi piacerebbe preferiscono avere solo una chiamata in questo modo:

mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

E assicurarsi che tutte le finally {} blocchi vengono chiamati da ogni thread dopo l'uscita.

So che questo è effettivamente previsto. Se l'applicazione viene chiusa da un thread separato (ad esempio il thread della GUI), il thread principale si fermerà semplicemente nelle sue tracce.

In breve, come faccio a garantire che un System.exit (0) o un JFrame.EXIT_ON_CLOSE causi ancora l'esecuzione definitiva di ogni blocco del thread?

risposta

8

Se non si hanno altre scelte di cambiamento di design allora che cosa potrebbe essere necessario è un JVM gancio di arresto, che può essere aggiunto per eseguire un pezzo di codice quando System.exit si chiama.

ganci arresto sono un costrutto speciale che consentono agli sviluppatori di spina in un pezzo di codice da eseguire quando la JVM si sta spegnendo. Questo è utile nei casi in cui è necessario eseguire operazioni di pulizia speciali nel caso in cui la VM si stacchi.

È possibile aggiungere un gancio di arresto, come indicato qui:

Runtime.getRuntime().addShutdownHook(Thread) 

Leggi di più riguardo i ganci di arresto qui:

http://java.dzone.com/articles/know-jvm-series-2-shutdown

parola di cautela:

È necessario tenere presente che non è garantito che gli arresti di arresto funzionino sempre. Se la JVM si arresta in modo anomalo a causa di un errore interno, , potrebbe verificarsi un arresto anomalo senza la possibilità di eseguire una singola istruzione . Inoltre, se l'O/S emette un segnale SIGKILL (http://en.wikipedia.org/wiki/SIGKILL) (kill -9 in Unix/Linux) o TerminateProcess (Windows), l'applicazione viene richiesta per terminare immediatamente senza attendere nemmeno le attività di pulizia . In aggiunta a quanto sopra, è anche possibile terminare la JVM senza consentire l'esecuzione dei hook di shutdown chiamando il metodoRunime.halt().

+1

Probabilmente importante notare che questo non è garantito per essere sempre eseguito (ad es. quando il jvm si arresta). – DannyMo

+1

@damo Sì, è un punto importante. Lasciatemi aggiungere alla risposta –

+1

Questo è un cattivo consiglio. I ganci di spegnimento dovrebbero ** mai ** essere usati come parte della normale routine di uscita. Sono solo una disposizione di ultima istanza, quando tutto il resto fallisce, per salvare ciò che può essere salvato. –

3

Se vi capita di avere queste discussioni che possono legalmente essere interrotta in qualsiasi momento, in qualsiasi punto del tutto all'interno del loro ciclo, in qualsiasi punto all'interno di qualsiasi metodo che essi invocano, e potrebbe vi avverto che è molto improbabile che lo fai, quindi è possibile stop tutti loro all'uscita del programma. In questo modo verrà generata un'eccezione in ogni thread e verranno eseguiti i blocchi finally.

Tuttavia, il modo corretto per raggiungere il tuo obiettivo e hanno GUI slegato dalla logica del programma, è quello di emettere un segnale singolo "uscita" dalla GUI, che attiverà tutti i cleanup applicazione, che è scritto in un classe completamente diversa. Se hai thread in esecuzione, implementa il meccanismo interrupt in ciascuno di essi.

Ci sono molti modi per ottenere la segnalazione di uscita. Ad esempio, il tuo codice aziendale potrebbe registrare un listener della GUI per un evento speciale, che innescherebbe la pulizia. Si potrebbe anche avere una discussione che non fa altro che await su un CountDownLatch che sarebbe countDown dalla GUI.

Per favore, non utilizzare ad ogni costo un gancio di arresto. Questo è il meccanismo più sporco che si possa immaginare, ed è lì solo come ultima risorsa, quando tutte le normali procedure di pulizia falliscono. È mai da utilizzare come parte della normale routine di spegnimento.

In sintesi, non esiste un modo reale per pulire l'arresto dell'applicazione. È necessario implementare meccanismi specifici per ogni specifica preoccupazione.

+0

Qualche esempio di codice? Ho sentito quello che stai dicendo e sembra logico (sto praticamente cercando esempi di questa stessa cosa) –

+0

potresti approfondire questo argomento o dare alcuni link o frasi a google? – Hoto

+1

@hoto 'Thread # interrupt 'è una delle cose su cui cercare google; 'CountDownLatch' è un altro; 'L'evento personalizzato AWT' è un terzo. –

0

con Java moderno, Window.dispose() su tutte le finestre delle applicazioni in grado di offrire possibilità più grazioso per uscire un'applicazione AWT di System.exit(0), vedere
https://docs.oracle.com/javase/8/docs/api/java/awt/Window.html#dispose--

/** Listens and closes AWT windows. 
* The class is implemented as singleton since only one is needed. 
*/ 
public class ExitListener extends WindowAdapter { 

    /** the instance object */ 
    private static final ExitListener INSTANCE = new ExitListener(); 

    // hide the constructor 
    private ExitListener() {} 

    /** retrieve the listener object */ 
    public static ExitListener getInstance() { 
    return INSTANCE; 
    } 

    @Override 
    public void windowClosing (final WindowEvent e) { 
    e.getWindow().dispose(); 
    } 
} 

e con le finestre

window.addWindowListener(ExitListener.getInstance()); 

Tuttavia, fare attenzione in ambienti avversi, vedere:
https://docs.oracle.com/javase/8/docs/api/java/awt/doc-files/AWTThreadIssues.html#Autoshutdown