How to stop java process gracefully?

JavaLinuxWindowsShellProcess

Java Problem Overview


How do I stop a Java process gracefully in Linux and Windows?

When does Runtime.getRuntime().addShutdownHook get called, and when does it not?

What about finalizers, do they help here?

Can I send some sort of signal to a Java process from a shell?

I am looking for preferably portable solutions.

Java Solutions


Solution 1 - Java

Shutdown hooks execute in all cases where the VM is not forcibly killed. So, if you were to issue a "standard" kill (SIGTERM from a kill command) then they will execute. Similarly, they will execute after calling System.exit(int).

However a hard kill (kill -9 or kill -SIGKILL) then they won't execute. Similarly (and obviously) they won't execute if you pull the power from the computer, drop it into a vat of boiling lava, or beat the CPU into pieces with a sledgehammer. You probably already knew that, though.

Finalizers really should run as well, but it's best not to rely on that for shutdown cleanup, but rather rely on your shutdown hooks to stop things cleanly. And, as always, be careful with deadlocks (I've seen far too many shutdown hooks hang the entire process)!

Solution 2 - Java

Ok, after all the possibilities I have chosen to work with "Java Monitoring and Management"
Overview is here
That allows you to control one application from another one in relatively easy way. You can call the controlling application from a script to stop controlled application gracefully before killing it.

Here is the simplified code:

Controlled application:
run it with the folowing VM parameters:
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=9999
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false

//ThreadMonitorMBean.java
public interface ThreadMonitorMBean
{
String getName();
void start();
void stop();
boolean isRunning();
}

// ThreadMonitor.java
public class ThreadMonitor implements ThreadMonitorMBean
{
private Thread m_thrd = null;

public ThreadMonitor(Thread thrd)
{
	m_thrd = thrd;
}

@Override
public String getName()
{
	return "JMX Controlled App";
}

@Override
public void start()
{
	// TODO: start application here
	System.out.println("remote start called");
}

@Override
public void stop()
{
	// TODO: stop application here
	System.out.println("remote stop called");
	
	m_thrd.interrupt();
}

public boolean isRunning()
{
	return Thread.currentThread().isAlive();
}

public static void main(String[] args)
{
	try
	{
		System.out.println("JMX started");
		
		ThreadMonitorMBean monitor = new ThreadMonitor(Thread.currentThread());

		MBeanServer server = ManagementFactory.getPlatformMBeanServer();

		ObjectName name = new ObjectName("com.example:type=ThreadMonitor");

		server.registerMBean(monitor, name);

		while(!Thread.interrupted())
		{
			// loop until interrupted
			System.out.println(".");
            try 
            {
                Thread.sleep(1000);
            } 
            catch(InterruptedException ex) 
            {
                Thread.currentThread().interrupt();
            }
		}
	}
	catch(Exception e)
	{
		e.printStackTrace();
	}
	finally
	{
		// TODO: some final clean up could be here also
		System.out.println("JMX stopped");
	}
}
}

Controlling application:
run it with the stop or start as the command line argument

public class ThreadMonitorConsole
{

public static void main(String[] args)
{
	try
	{	
		// connecting to JMX
		System.out.println("Connect to JMX service.");
		JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://:9999/jmxrmi");
		JMXConnector jmxc = JMXConnectorFactory.connect(url, null);
		MBeanServerConnection mbsc = jmxc.getMBeanServerConnection();
		
		// Construct proxy for the the MBean object
		ObjectName mbeanName = new ObjectName("com.example:type=ThreadMonitor");
		ThreadMonitorMBean mbeanProxy = JMX.newMBeanProxy(mbsc, mbeanName, ThreadMonitorMBean.class, true);

		System.out.println("Connected to: "+mbeanProxy.getName()+", the app is "+(mbeanProxy.isRunning() ? "" : "not ")+"running");
		
		// parse command line arguments
		if(args[0].equalsIgnoreCase("start"))
		{
			System.out.println("Invoke \"start\" method");
			mbeanProxy.start();
		}
		else if(args[0].equalsIgnoreCase("stop"))
		{
			System.out.println("Invoke \"stop\" method");
			mbeanProxy.stop();
		}
		
		// clean up and exit
		jmxc.close();
		System.out.println("Done.");	
	}
	catch(Exception e)
	{
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
}
}


That's it. :-)

Solution 3 - Java

An another way: your application can open a server socet and wait for an information arrived to it. For example a string with a "magic" word :) and then react to make shutdown: System.exit(). You can send such information to the socke using an external application like telnet.

Solution 4 - Java

Here is a bit tricky, but portable solution:

  • In your application implement a shutdown hook
  • When you want to shut down your JVM gracefully, install a Java Agent that calls System.exit() using the Attach API.

I implemented the Java Agent. It is available on Github: https://github.com/everit-org/javaagent-shutdown

Detailed description about the solution is available here: https://everitorg.wordpress.com/2016/06/15/shutting-down-a-jvm-process/

Solution 5 - Java

Similar Question Here

Finalizers in Java are bad. They add a lot of overhead to garbage collection. Avoid them whenever possible.

The shutdownHook will only get called when the VM is shutting down. I think it very well may do what you want.

Solution 6 - Java

Signalling in Linux can be done with "kill" (man kill for the available signals), you'd need the process ID to do that. (ps ax | grep java) or something like that, or store the process id when the process gets created (this is used in most linux startup files, see /etc/init.d)

Portable signalling can be done by integrating a SocketServer in your java application. It's not that difficult and gives you the freedom to send any command you want.

If you meant finally clauses in stead of finalizers; they do not get extecuted when System.exit() is called. Finalizers should work, but shouldn't really do anything more significant but print a debug statement. They're dangerous.

Solution 7 - Java

Thanks for you answers. Shutdown hooks seams like something that would work in my case. But I also bumped into the thing called Monitoring and Management beans:
http://java.sun.com/j2se/1.5.0/docs/guide/management/overview.html
That gives some nice possibilities, for remote monitoring, and manipulation of the java process. (Was introduced in Java 5)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMa99uSView Question on Stackoverflow
Solution 1 - JavajsightView Answer on Stackoverflow
Solution 2 - JavaMa99uSView Answer on Stackoverflow
Solution 3 - JavaErmakView Answer on Stackoverflow
Solution 4 - JavaBalazs ZsoldosView Answer on Stackoverflow
Solution 5 - JavaSteve gView Answer on Stackoverflow
Solution 6 - JavaextraneonView Answer on Stackoverflow
Solution 7 - JavaMa99uSView Answer on Stackoverflow