Use JVM Shutdown Hooks to Optimize Resources

Use JVM Shutdown Hooks to Optimize Resources

ave you ever found yourself in the following scenario:

  1. You’ve created server-side Java applications for a production environment.
  2. You write a program that allocates external resources: connections to a database using JDBC.
  3. A user prematurely terminates the program (by typing control-C, for example).
  4. The external database server eventually needs to be restarted because all client connections are allocated but not freed.

If this sounds familiar, it’s time to explore a seldom-used feature of the Java Virtual Machine (JVM): the ability to register JVM shutdown hooks that execute before a JVM shuts down. In the above scenario, JVM shutdown hooks could perform cleanup processing to free the external resources. This 10-Minute Solution offers two quick demonstrations (one simple, one more complex) of how to use these hooks in your own Java programs.

In production environments, JVMs are killed and restarted either automatically by network management systems or manually by a network administrator. When a JVM is killed, it is often necessary to perform some cleanup work before the JVM finishes shutting down.

JVM shutdown hooks provide a clean and simple mechanism for registering application-specific behavior that performs cleanup work when a JVM terminates.

A Simple Example: the SimpleHook Class
You implement JVM shutdown hooks using a separate class that extends the Thread class (click here to download the accompanying source code for this Solution). When you register an instance of this separate class with a JVM (you will learn how to do this later), the shutdown thread class starts when the JVM terminates.

The non-public class MyShutdown is defined at the bottom of the file (included in the source code download):

class MyShutdown extends Thread {    public MyShutdown(SimpleHook managedClass) {        super();        this.managedClass = managedClass;    }    private SimpleHook managedClass;    public void run() {        System.out.println("MyShutDown thread started");        try {            managedClass.freeResources();        } catch (Exception ee) {            ee.printStackTrace();        }    }}

Notice that the constructor requires a reference to the managed application class. In the design pattern this Solution (and I) use, the managed parent class is expected to define a method freeResources(). To be tidy, you could define a separate interface that defines the freeResources() method signature and have managed classes implement this interface. However, to keep this example simple, I just concentrate on using JVM shutdown hooks.

The constructor for the managed class SimpleHook creates an instance of the MyShutdown class and registers this instance with the JVM:

    public SimpleHook() {        // set up service termination hook (gets called        // when the JVM terminates from a signal):        MyShutdown sh = new MyShutdown(this);        Runtime.getRuntime().addShutdownHook(sh);    }

See the source file for the complete code.

A More Complex Example: the JdbcHook Class
You now understand how to write JVM shutdown hooks. The slightly more complex example in this section shows a common use for JVM shutdown hooks: freeing external (to the JVM) database connections.

A few years ago, I wrote some Java code and made an error: database connections to my local PostgreSQL database server were not getting closed. After restarting my database server, I noticed the coding error and fixed it. This experience reinforced the importance of using a coding pattern to ensure that database connections get properly closed.

For example, for infrequent database access, the following code pattern works well:

        Connection conn = null;        Statement stmt = null;        try {            conn =              DriverManager.getConnection(DBurl, DBuser,                                                                      DBpassword);            stmt = conn.createStatement();            stmt.executeUpdate("insert into ErrorDB values ('"                          + topic + "', '" +                             error + "', " +                              System.currentTimeMillis() + ", '')");        } catch (Exception ee) {            ee.printStackTrace();        } finally {            if (stmt != null) {                try {                    stmt.close();                } catch (Exception e2) {                }            }            if (conn != null) {                try {                    conn.close();                } catch (Exception e2) {                }            }        }

This coding pattern almost guarantees that external database connection resources will be freed, but it is inappropriate for applications that require frequent database access because of the overhead of repeatedly opening and closing database connections.

A better design pattern is to create a database connection and reuse it. However, you must insure that the database connection eventually gets closed. This is a good use for JVM shutdown hooks!

The example in the file (included in the source code download) is simple enough for me to list most of the code here. First, you define the database connection information:

    private Connection conn = null;    public static String DBurl =  "jdbc:postgresql://localhost:5432/test?user=postgres";    public static String DBdriver =        "org.postgresql.Driver";    static {        /**         * Check to see if parameters are set         * at runtime to override defaults:         */        try {            DBurl = System.getProperty("DBurl", DBurl);            DBdriver = System.getProperty("DBdriver",                                                                      DBdriver);        } catch (Exception ee) {            ee.printStackTrace();        }    }

You hard coded the database connection URL, but check to see if this information is overridden at runtime (e.g., by using a command line argument such as -DDBurl=jdbc:...). The file contains a non-public class MyJdbcConnectionShutdownHook that is almost identical to the class MyShutdown (derived from the Thread class) that you used in the previous section. Look at the source file for details.

The constructor for class JdbcHook registers the shutdown hook class with the JVM:

    public JdbcHook() throws Exception {        Class.forName(DBdriver);        conn = DriverManager.getConnection(DBurl);        // set up service termination hook (gets called        // when the JVM terminates from a signal):        MyJdbcConnectionShutdownHook sh =             new MyJdbcConnectionShutdownHook(this);        Runtime.getRuntime().addShutdownHook(sh);    }

When the JVM terminates, the method freeResources() is called:

    public void freeResources() {        try {            if (conn != null && conn.isClosed()==false) {                conn.close();            }        } catch (Exception ee) {            System.out.println("Error freeing resources: " +                                             ee);            ee.printStackTrace();        }    }

Think Beyond Your Development Environment
As Java developers, we tend to “live” in our development environments, where freeing resources is usually not an issue. However, a proper architecture takes into account the problems that occur when systems must run continually. You should get in the habit of writing all of your Java code as if it will be deployed in a production environment.

Share the Post:
XDR solutions

The Benefits of Using XDR Solutions

Cybercriminals constantly adapt their strategies, developing newer, more powerful, and intelligent ways to attack your network. Since security professionals must innovate as well, more conventional endpoint detection solutions have evolved

AI is revolutionizing fraud detection

How AI is Revolutionizing Fraud Detection

Artificial intelligence – commonly known as AI – means a form of technology with multiple uses. As a result, it has become extremely valuable to a number of businesses across

AI innovation

Companies Leading AI Innovation in 2023

Artificial intelligence (AI) has been transforming industries and revolutionizing business operations. AI’s potential to enhance efficiency and productivity has become crucial to many businesses. As we move into 2023, several

data fivetran pricing

Fivetran Pricing Explained

One of the biggest trends of the 21st century is the massive surge in analytics. Analytics is the process of utilizing data to drive future decision-making. With so much of

kubernetes logging

Kubernetes Logging: What You Need to Know

Kubernetes from Google is one of the most popular open-source and free container management solutions made to make managing and deploying applications easier. It has a solid architecture that makes

ransomware cyber attack

Why Is Ransomware Such a Major Threat?

One of the most significant cyber threats faced by modern organizations is a ransomware attack. Ransomware attacks have grown in both sophistication and frequency over the past few years, forcing

data dictionary

Tools You Need to Make a Data Dictionary

Data dictionaries are crucial for organizations of all sizes that deal with large amounts of data. they are centralized repositories of all the data in organizations, including metadata such as