终止Java Process对象



我有一个跨平台(Linux和Windows)程序,目前在Java 7上运行。该程序将使用ProcessBuilder启动一个或多个worker作为进程(使用这里的指令):

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();

采用这种方法的原因是为了解决旧系统的一个问题,即在线程中运行worker。然而,由于我们正在运行的代码的性质,工作线程可能会进入一个无法退出的循环。由于Java不支持终止线程的想法,我们转移到一个完全独立的进程,假设Java实际上可以杀死一个进程。

然而,在Java 7中似乎不是这样的——Process.destroy()发送一个SIGTERM,而不是SIGKILL,并且我们停滞的工作线程并没有像我们期望的那样被杀死。Java 8实现了process . destroy强行(),它可以解决这个问题,但是升级核心Java版本可能会引入许多错误,升级是我们希望尽可能避免的事情。

大多数其他解决方案涉及到反射到UNIXProcess类,获取pid,并将kill命令管道传递给shell。然而,这对我们来说不起作用,因为我们在Windows上运行,Process没有任何pid的掌握,并且进一步迫使我们包含特定于操作系统的代码路径,这是非常不希望的。

是否有一些可靠的方法让Java终止某事?

你可以试试这个API SIGAR。

示例代码:

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);
    }
}

代码来源:链接

在我的情况下,由于我同时编写父进程和子进程,解决方案是添加一个停止JVM的ShutdownHook(简单的System.exit(1)是不够的):

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

在此之后,当接收到SIGTERM时,进程将终止,就像它已经被父进程发送了SIGKILL一样。

相关内容

最新更新