Java-Anwendung sauber beenden mit addShutdownHook

Bei einfachen Java-Anwendungen macht man sich typischerweise wenig Gedanken um das saubere Beenden aller Prozesse. Man geht davon aus, dass der Nutzer weiß, was er tut, wenn er auf Beenden klickt und fragt zur Not vorher nochmal nach, ob er tatsächlich fortfahren will. Anders sieht das jedoch aus, wenn man mehrere Threads verwaltet - wie das zum Beispiel bei Serveranwendungen der Fall ist. Dann möchte man vor dem tatsächlichen Beenden lieber doch noch die einen oder anderen Aufräumarbeiten durchführen - zum Beispiel Logdateien flushen, laufende Serveranfragen beantworten oder temporäre Dateien wegräumen.

Die JVM-Runtime bietet für solche Fälle die Möglichkeit, sogenannte Shutdown-Hooks via Runtime.getRuntime().addShutdownHook() zu registrieren. Wenn die JVM beendet wird, werden die registrierten Hooks ausgeführt (im Grunde sind es Threads, deren run()-Methode aufgerufen wird).

Im folgenden Beispiel habe ich mal eine kleine Vorlage gebastelt, in der man sieht, wie man das ganze verwenden kann. In der Methode "startupMain()" implementiert man alle Initialisierungen, die beim Programmstart ausgeführt werden sollen, in der Methode "runMain()" führt man dann die tatsächliche Anwendung aus, während in der Methode "shutdownMain()" notwendige Deinitialisierungen durchgeführt werden können.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
public class Main extends Object implements Runnable {

    // singleton instance
    protected static Main fInstance = null;

    static {
        // create singleton instance
        fInstance = new Main();
    }

    // prevent external instantiation
    protected Main() {
        super();
    }

    public static Main getInstance() {
        return fInstance;
    }

    public static void main(String[] args) {
        Main lMain = Main.getInstance();

        // call startup code
        lMain.startupMain(args);

        // register shutdown code
        Runtime.getRuntime().addShutdownHook(new Thread(lMain));
       
        // call main code
        lMain.runMain();
    }

    @Override
    public void run() {
        // call shutdown code
        shutdownMain();
    }    

    public synchronized void startupMain(String[] aArguments) {
        // startup code
        // ...
    }

    public synchronized void shutdownMain() {
        // shutdown code
        // ...
    }

    public void runMain() {
        // main code
        // ...
    }

}

Als Test habe ich mir eine einfache Anwendung geschrieben, die beim Starten das Wort "start", während des Laufens in einer Endlosschleife das Wort "sleep" und beim Beenden das Wort "stop" schreibt. Die drei Methoden sehen dabei wie folgt aus:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    public synchronized void startupMain(String[] aArguments) {
        // startup code
        // ...
        System.out.println("start");
    }

    public synchronized void shutdownMain() {
        // shutdown code
        // ...
        System.out.println("stop");
    }

    public void runMain() {
        // main code
        // ...
        while (true) {
            System.out.println("sleep");
            try {
                Thread.sleep(1000);
            }
            catch (Exception e) {}
        }
    }

Nach dem Starten verwende ich den Linuxbefehl "kill -SIGINT <Prozess-ID>", um die Anwendung wieder zu beenden. Dabei wird vor dem tatsächlichen Beenden noch der Shutdown-Hook ausgeführt. Im folgenden kleinen Video habe ich das ganze mal demonstriert:

Wie ihr seht, kann man mit einfachen Mitteln Java-Anwendungen sauber und ordentlich beenden. Es ist übrigens auch möglich, mehrere Shutdown-Hooks zu registrieren. Da jedoch deren Ausführungsreihenfolge nicht definiert ist, ist anzuraten, nur einen Shutdown-Hook für die gesamte Anwendung zu verwenden und in diesem zur Not weiteren Cleanup-Code aufzurufen. Da der Shutdown-Hook ein Thread ist, müsst ihr euch zudem um Themen wie Threadsicherheit kümmern.

Saubere Grüße, Kenny

Schreibe einen Kommentar

Um Ihnen beim weiteren Kommentieren auf dieser Webseite die erneute Eingabe Ihrer Daten zu ersparen, wird beim Absenden Ihres Kommentars ein Cookie an Ihren Browser gesendet und von diesem gespeichert. Mit dem Absenden eines Kommentars auf dieser Webseite stimmen Sie der Speicherung und Übertragung dieses Cookies explizit zu.

Pflichtfelder sind mit * markiert.