preface

1. Basic Overview

The program is easy to start, usually do some preloading of resources. However, sometimes when closing, the preloaded resources are not completely cleaned up at startup, so hook functions can be used to do this.

2. Classification of JVM shutdown scenarios

Take a quick look at this image, courtesy of BarryWang of blogosphere, which is specially illustrated here.

img

As can be seen from the above, JVM shutdowns are divided into three main categories, the first is normal shutdowns, the second is abnormal shutdowns, and the third is forced shutdowns. For the first two methods we can use the hook function to gracefully close, but the forced closure does not work.

With these concepts in mind, let’s go straight to a case study and analyze it.

Code to demonstrate the hook function

1. JVM shuts down properly

Let’s just look at the code,

public class Test {

 public void start(a){

  Runtime.getRuntime().addShutdownHook(new Thread(()-> 

    System.out.println("The hook function is executed and can close the resource here.")

  ));

 }

 public static void main(String[] args) throws Exception{

  new Test().start();

  System.out.println("Main application executing");

 }

}

// Console output

// The main application is executing

// The hook function is executed and the resource can be closed here

Copy the code

As you can see from the console print, the main application will call the hook function after execution, which will formally shut down the JVM.

2. Abnormal shutdown

We can set the heap size to 20M, and then create a 500M object in the code, which will generate OOM. The argument is -xmx20m;

public class Test {

 public void start(a){

  Runtime.getRuntime().addShutdownHook(new Thread(()-> 

    System.out.println("The hook function is executed and can close the resource here.")

  ));

 }

 public static void main(String[] args) throws Exception{

  new Test().start();

  System.out.println("Main application executing");

  Runtime.getRuntime().halt(1);

  byte[] b = new byte[500*1024*1024];

 }

}

// Console output

// The main application is executing

// The hook function is executed and the resource can be closed here

Copy the code

As you can see from the console, the hook function is still called when the exception is closed.

3. Forcibly close

Here we use Runtime.geTruntime ().halt() to demonstrate a strong shutdown. The difference between this method and system.exit is that system.exit executes the hook function, but runtime.getruntime ().halt() does not.

public class Test {

 public void start(a){

  Runtime.getRuntime().addShutdownHook(new Thread(()-> 

    System.out.println("The hook function is executed and can close the resource here.")

  ));

 }

 public static void main(String[] args) throws Exception{

  new Test().start();

  System.out.println("Main application executing");

  Runtime.getRuntime().halt(1);

 }

}

// Console output

// The main application is executing

Copy the code

As you can see from the output of the code above, calling Runtime.geTruntime ().halt(1) forces the JVM to shut down before the hook function can execute. Using system.exit will still execute. So system.exit is commonly used to shut down the JVM.

4. Remove the hook function

The hook functions shown above are sometimes easy to remove.

public class Test {

 public static void main(String[] args) throws Exception{

  //new Test().start();

  Thread willNotRun = new Thread(() -> 

   System.out.println("Won't run!"));

  Runtime.getRuntime().addShutdownHook(willNotRun);

  System.out.println("Main application executing");

  Runtime.getRuntime().removeShutdownHook(willNotRun);

 }

}

// Console output

// The main application is executing

Copy the code

OK, the basic operation of the hook function is left here. It is relatively easy to use, but I have seen the Spring startup process before, so I went to that startup process again and found that the hook function is also used.

2. Typical application scenarios

1. Use Spring

When Spring closes a context, it can use hook functions to close residual resources. You do this by registering a hook function using ApplicationContext.

ApplicationContext.registerShutdownHook();

// This code can be used to analyze

public void registerShutdownHook(a) {

    if (this.shutdownHook == null) {

      this.shutdownHook = new Thread() {

        @Override

        public void run(a) {

          //Spring closes normally

          doClose();

        }

      };

      // Call the hook function to close the residual resource

      Runtime.getRuntime().addShutdownHook(this.shutdownHook);

    }

}

Copy the code

From the source, we can see that Spring actually calls Java hook functions to close.

2. Other uses

I have also seen spark and Hadoop shut down in a number of blogs, but since I have not seen the source code, I will draw a conclusion here. For other usage scenarios, it is basically implemented by calling Java hook functions.

conclusion

When closing the JVM, we can wrap hook functions to gracefully close the thread. However, the following aspects need to be paid attention to when using:

The hook function is essentially a thread

Multiple hooks execute concurrently, and the JVM does not guarantee their order; Therefore, it is best to perform a series of operations in a single hook.

2. No new hooks can be created in hooks

In closing a hook, you cannot register or remove the hook or the JVM will throw an IllegalStateException. You can’t use system.exit () either, as mentioned earlier system.exit () triggers the hook function, but Runtime.halt() can, because runtime.halt () can force closure.

3. Preferably no time-consuming operations in the hook

Hook functions are mainly used to close residual resources, so don’t have time-consuming operations.

OK, let me do that.