3

I have a cross-platform (Linux and Windows) program, currently running on Java 7. The program will launch one or more workers as Processes using ProcessBuilder (using instructions from here):

String javaHome = System.getProperty("java.home");
String javaBin = javaHome + File.separator + "bin" + File.separator + "java";
String classpath = System.getProperty("java.class.path");
String className = MyClass.class.getCanonicalName();

ProcessBuilder pb = new ProcessBuilder(javaBin, "-cp", classpath, className);
pb.directory(null);
pb.inheritIO();

Process p = pb.start();

The reason for this approach was designed to solve an issue with the older system, which ran the workers in threads. However, due to the nature of the code we're running, it's possible for the workers to enter a loop from which they won't exit. Since Java does not support the idea of terminating a thread, we moved to a completely separate process under the assumption that Java could actually kill a process.

However, it appears that isn't true in Java 7 - Process.destroy() sends a SIGTERM, not a SIGKILL, and our stalled workers aren't being killed as we'd expect. Java 8 implemented Process.destroyForcibly(), which would solve the problem, but upgrading the core Java version is likely to introduce a number of bugs, and upgrading is something we'd like to avoid if at all possible.

Most other solutions involve reflecting into the UNIXProcess class, getting the pid, and piping a kill command to the shell. However, this won't work for us as we run on Windows, where Process does not have any grasp of a pid, and further forces us to include OS-specific code paths which is extremely undesirable.

Is there some reliable way to get Java to terminate something?

Basket
  • 31
  • 4
  • I think the only option you have is to use Runtime.exec() and the Kill Functions of Linux or Windows . – Kami Jul 28 '15 at 20:10
  • But there isn't a reliable way to get the processID in windows, so how can I figure out which process to kill? Other answers specifically leveraged UNIXProcess as noted in the question. – Basket Jul 28 '15 at 20:23
  • 1
    Fyi, upgrading java from 7 to 8 is highly unlikely to introduce number of bugs as you expect. – John Jul 28 '15 at 20:29
  • Can you design such ipc mechanism to notify processes that should be killed rather then trying to kill them from the outside? These processes would then self terminate. – John Jul 28 '15 at 20:32
  • SIGKILL is functionally a process notification system, and probably one which takes place at a higher priority than within the code. The problem is the process being in a funked up state to the point where it doesn't respect the SIGKILL. Ex I added a ShutdownHook which invoked System.exit(1), but the worker doesn't actually exit even though it enters the hook. – Basket Jul 28 '15 at 20:35
  • In that case, try replacing System.exit with Runtime.getRuntime().halt() in your shutdown hook. This should stop jvm. – John Jul 28 '15 at 20:41
  • 1
    Java 7 is end of public support, upgrading to Java 8 if not Java 9 is likely to be something you will have to do anyway. – Peter Lawrey Jul 28 '15 at 21:32
  • Calling runtime.halt() did it. User, if you want to submit that as an answer I'lll accept it, I'll write it myself in 24 hours if not so other people don't have to scour the comments. Thanks! – Basket Jul 29 '15 at 14:41

2 Answers2

1

You can try this API SIGAR.

Sample code:

final Sigar sigar = new Sigar();
final long[] processes = sigar.getProcList();

for (final long processId : processes) {
    System.out.println(processId + " = " + ProcUtil.getDescription(sigar, processId));
    final String processDescription = ProcUtil.getDescription(sigar, processId);

    if(processDescription.contains("notepad.exe")){
        System.out.println("Found notepad.exe with id [" + processId + "] - KILLING IT!");
        sigar.kill(processId, -9);
    }
}

Code source:Link

Kami
  • 459
  • 1
  • 6
  • 27
  • Is that going to work if I spawn 5 worker threads in the same class? The code from the question is run in a loop to spawn workers. How can I know which of the Process instances maps to the specific worker? – Basket Jul 28 '15 at 20:22
  • Hi i think you have to try that :) , had no time to test the API. – Kami Jul 28 '15 at 20:26
0

The solution in my case, since I was writing both the parent and the child processes, was to add a ShutdownHook which halted the JVM (a simple System.exit(1) was not sufficient):

Runtime.getRuntime().addShutdownHook(new Thread() {
        @Override
        public void run() {
            Runtime.getRuntime().halt(5);
        }
});

After this, when a SIGTERM was received the process would terminate, as though it had been sent SIGKILL by the parent process.

Basket
  • 31
  • 4