I have a Java application that I want to be started on my Mac whenever I start the machine. The application should be shut down gracefully whenever the machine is shut down.
I added a shutdown hook in the main method:
Runtime.getRuntime().addShutdownHook(new Thread(new ShutdownHook(scheduler)));
ShutdownHook
class looks like this:
public class ShutdownHook implements Runnable {
private final static Logger LOGGER = LoggerFactory.getLogger("Shutdown Hook");
private final Scheduler scheduler;
public ShutdownHook(Scheduler scheduler) {
this.scheduler = scheduler;
}
@Override
public void run() {
LOGGER.debug("Starting to shot down the application");
try {
scheduler.shutdown();
} catch (final SchedulerException e) {
LOGGER.error("An error occurred while trying to shut down the scheduler", e);
}
LOGGER.info("Exiting the shutdown hook");
}
}
Then I built the application into an executable JAR and added it to the list of "Login items".
The application is started when I log in.
However, the shutdown hook is not executed when the machine shuts down.
How can I make sure that when I shut down the machine using the menu item shown below, a running Java application detects that the machine is shutting down?
Update 1:
As far as I understand, one way to fix the error is to use launchd
to start the Java program. I wrote the plist
file below.
The next question is how to make sure that launchd
runs the application described in that plist
file?
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>ExitTimeOut</key>
<integer>300</integer>
<key>StandardErrorPath</key>
<string>/Users/XXXXXX/sw/wordcounter-daemon/error</string>
<key>Label</key>
<string>com.dpisarenko.wordcounterdaemon</string>
<key>ProgramArguments</key>
<array>
<string>/usr/bin/java</string>
<string>-jar</string>
<string>/Users/XXXXXXX/sw/wordcounter-daemon/wordcounter-daemon-0.1-jar-with-dependencies.jar</string>
</array>
</dict>
</plist>
To shutdown computer in Java programming, you have to use the command shutdown -s. You can also specify the time in seconds, after which you want to turn off or shutdown the PC, using shutdown -s -t seconds. Where seconds refers to the number of seconds. Note - To shutdown the computer, use shutdown -s.
There are two ways to terminate the JVM instance from the running application: Calling the exit() method, which initiates the JVM normal shutdown sequence: run all registered shutdown hooks; run all uninvoked finalizers; then end the JVM instance. Calling the halt() method, which ends the JVM instance immediately.
Use the -stop command to stop the JVM controller. You must supply the name of the JVM controller as an argument for the JVM controller you want to stop. You will receive an error if a JVM controller with the specified name is not running. There is no additional option.
Usually Unix-style systems will shutdown a daemon process in two steps:
SIGTERM
signal send to process
SIGKILL
signal send to process if the process still runs after X seconds after point 1
This answer explains how to configure ExitTimeOut
value which controlls time between these two signals on MacOS.
The behaviour for non-daemon processes might be different and this might be the reason your process is not executing JVM shutdown hook. The JVM probably received SIGKILL
and by design a user-space process can't handle this signal. Potentially you want to convert your process to a daemon.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With