杀死Java进程对象

3

我有一个跨平台(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();

这种方法的设计初衷是为了解决旧系统中运行工作线程时出现的问题。然而,由于我们运行的代码的性质,工作线程有可能进入一个无法退出的循环。由于Java不支持终止线程的想法,我们转移到了一个完全独立的进程下,假设Java实际上能够杀死一个进程。
然而,看起来在Java 7中这并不成立 - Process.destroy() 发送一个SIGTERM信号,而不是SIGKILL,我们的停滞工人没有像我们预期的那样被杀死。Java 8实现了Process.destroyForcibly(),可以解决这个问题,但升级核心Java版本可能会引入许多错误,而我们希望尽可能避免升级。
大多数其他解决方案涉及反射UNIXProcess类、获取pid,并将kill命令传递到shell中。然而,这对我们来说行不通,因为我们在Windows上运行,在那里Process没有任何关于pid的了解,而且还迫使我们包含特定于操作系统的代码路径,这是极其不可取的。
有没有一种可靠的方法让Java终止某些东西?

但是在Windows中没有可靠的方法来获取进程ID,那么我该如何找出要终止哪个进程呢?其他答案特别利用了问题中提到的UNIXProcess。 - Basket
1
请注意,将Java从7升级到8不太可能像您预期的那样引入大量错误。 - John
在这种情况下,请尝试在您的关闭挂钩中将System.exit替换为Runtime.getRuntime().halt()。这应该会停止JVM。 - John
1
Java 7已经结束公共支持,升级到Java 8或者Java 9可能是你必须要做的事情。 - Peter Lawrey
调用runtime.halt()方法就可以了。如果您想将其作为答案提交,我会接受的。如果24小时后还没有提交,我会自己写下来,这样其他人就不必浏览评论了。谢谢! - Basket
显示剩余3条评论
2个回答

1
你可以尝试使用这个 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);
    }
}

代码来源:Link


如果我在同一个类中生成5个工作线程,那么这是否能够工作?问题中的代码在循环中运行以生成<n>个工作线程。我如何知道哪个进程实例映射到特定的工作线程? - Basket
嗨,我认为你应该试一下 :) ,我没有时间测试API。 - Kami

0
在我的情况下,由于我编写了父进程和子进程,所以解决方案是添加一个ShutdownHook来停止JVM(简单的System.exit(1)是不够的):
Runtime.getRuntime().addShutdownHook(new Thread() {
        @Override
        public void run() {
            Runtime.getRuntime().halt(5);
        }
});

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接