Thêm Shutdown Hook cho JVM Application

Khi System.exit() method được gọi, nó sẽ dừng máy ảo của Java đang chạy (JVM), nhưng trước khi dừng JVM sẽ thực thi các shutdown hook đã được đăng ký trước đó. Trong bài viết này, chúng ta sẽ tìm hiểu xem shutdown hook là gì? cách sử dụng cũng như cách tạo các shutdown hook và đăng ký với JVM.

JVM Shutdown

JVM có thể bị dừng có kiểm soát hoặc đột ngột do có một lỗi bất thường xảy ra.

Quá trình dừng JVM có kiểm soát là một trong những trường hợp sau:

  • Khi non-deamon thread cuối cùng hoàn tất và chấm dứt hoạt động. Ví dụ khi main thread dừng, JVM sẽ bắt đầu xử lý quá trình xử lý dừng tất cả các thread đang hoạt động.
  • Gửi tính hiệu ngắt từ hệ điều hành. Ví dụ, chúng ta hay tắt chương trình bằng tổ hợp phím Ctrl + C hoặc tắt hệ điều hành.
  • Gọi System.exit() method trong Java code.

Mặc dù chúng ta luôn có gắng để dừng JVM có kiểm soát, thế nhưng đôi lúc, nó cũng bị tắt đột ngột như:

  • Gửii tín hiệu tiêu hủy chương trình cho hệ điều hành. Ví dụ thực thi lệnh kill -9 <jvm-pid>.
  • Gọi Runtime.getRuntime.halt() từ Java code.
  • Máy chủ chết bất ngờ, ví dụ nguồn điện cấp cho máy chủ bị mất. 

Shutdown hook là gì?

JVM cho phép chúng ta đăng ký các function để thực thi trước khi nó dừng hẳn. Những function này thường được sử dụng để giải phóng các tài nguyên mà chương trình đang nắm giữ, hoặc một số tác vụ cần thiết để đảm bảo chương trình sẽ không gây lỗi sau khi dừng hoạt động. Những function này được gọi là shutdown hook.

Khi JVM bắt đầu xử ký quá trình shutdown, nó sẽ thực thi các shutdown hook theo một thứ tự không xác định. Khi tất cả các hook hoàn thành, JVM sẽ tạm dừng cho đến khi dừng hẳn.

Tạo shutdown hook

Để tạo và đăng ký shutdown hook với JVM, chúng ta có thể sử dụng Runtime.getRuntime().addShutdownHook() method:

public class Main {

     public static void main(String []args){
        Thread printingHook = new Thread(() -> System.out.println("In the middle of a shutdown"));
        System.out.println("Starting");
        Runtime.getRuntime().addShutdownHook(printingHook);

     System.exit(0);
     }
}
Output:
Starting
In the middle of a shutdown

Lưu ý, việc thực thi các hook phải được thực thi bởi JVM, nếu chúng ta cố ý khởi chạy nó trước đó, Java sẽ ném ra exception

public class Main {

     public static void main(String []args){
        Thread printingHook = new Thread(() ->
                          System.out.println("In the middle of a shutdown"));
        printingHook.start();
        Runtime.getRuntime().addShutdownHook(printingHook );
        System.exit(0);
     }
}

Output:

In the middle of a shutdown Exception in thread “main” java.lang.IllegalArgumentException: Hook already running at java.lang.ApplicationShutdownHooks.add(ApplicationShutdownHooks.java:69) at java.lang.Runtime.addShutdownHook(Runtime.java:211) at Main.main(Main.java:6)

Và cũng chắc rằng một shutdown hook chỉ được phép đăng ký một lần với JVM.

public class Main {

     public static void main(String []args){
        Thread printingHook = new Thread(() ->
                          System.out.println("In the middle of a shutdown"));
        Runtime.getRuntime().addShutdownHook(printingHook);
        Runtime.getRuntime().addShutdownHook(printingHook);
        System.exit(0);
     }
}

Output:

In the middle of a shutdown
Exception in thread “main” java.lang.IllegalArgumentException: Hook previously registered at java.lang.ApplicationShutdownHooks.add(ApplicationShutdownHooks.java:72) at java.lang.Runtime.addShutdownHook(Runtime.java:211) at Main.main(Main.java:7)

Xóa Shutdown hook

Java cung cấp Runtime.getRuntime().removeShutdownHook() method cho phép xóa một shutdown hook sau khi nó đã được đăng ký với JVM.

public class Main {

     public static void main(String []args){
        Thread willNotRun = new Thread(() -> System.out.println("Won't run!"));
        Runtime.getRuntime().addShutdownHook(willNotRun);
        boolean isRemove = Runtime.getRuntime().removeShutdownHook(willNotRun); //TRUE
        System.exit(0);
     }
}

Note: JVM chỉ thực thi các shutdown hook trong các trường hợp bình thường, nhưng khi JVM bị dừng một cách đột ngột (hệ điều hành tắt đột ngột) thì nó sẽ không có đủ thời gian để thực thi các shutdown hook, hay gọi halt() method cũng cho kết quả tương tự.

Thread haltedHook = new Thread(() -> System.out.println("Halted abruptly"));
Runtime.getRuntime().addShutdownHook(haltedHook);
         
Runtime.getRuntime().halt(129);

Tóm lược

Như vậy, qua bài viết này chúng ta đã biết thêm về shutdown hook, đây là một tính năng khá tiện lợi cho phép chúng ta thực thi các thao tác cuối cùng trước khi chương trình dừng hẳn như giải phóng các tài nguyên, hoặc thông báo cho các hệ thống giao tiếp với chương trình rằng nó sẽ ngưng hoặc động.

Nguồn tham khảo

https://www.baeldung.com/java-runtime-halt-vs-system-exit

https://www.baeldung.com/jvm-shutdown-hooks

0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x