简体   繁体   中英

Killing a Java Process object

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?

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

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM