5

我有一个 Java webstart 进程,它是 Windows 批处理脚本的一部分。在这种情况下,我在批处理脚本中使用 javaws 命令。此匹配脚本 (start.bat) 使用“apache commons exec”以编程方式调用。在某些情况下,javaws 调用的 java 进程挂起,我必须从批处理脚本 start.bat 开始杀死整个进程线程。是否有通过 apache commons exec 杀死整个进程树的编程方式?

我试过使用“execWatchdog.destroyProcess();” 在“start.bat”脚本上。但是,它只会杀死 start.bat 进程,而不是整个进程树。

有没有办法通过 apache-commons-exec 或类似代码杀死整个进程树?

我已经看到了这个问题Performing equivalent of "Kill Process Tree" in c++ on windows that perform an equivalent task in c++。我想知道是否有人实现了通过 JNI 调用 Windows 本机系统调用。

4

4 回答 4

8

终于得到了一些可行的东西,即使它是一种迂回的方式。

Apache Commons Exec API 包含返回 java.lang.Process 对象的 CommandLauncher 类。感谢链接

这里是从 java.lang.Process 获取 windows 进程 ID的链接。这使用 JNA 库。

最后是进程ID,这里是杀死进程树的命令字符串 //String killCmd = "taskkill /F /T /PID " + JNAHandler.getPid(process);

于 2011-10-02T16:30:58.800 回答
2

不幸的是,正如您所发现的,没有一种纯粹的 Java 方法可以做到这一点。您将不得不求助于本机命令或 JNI 库,所有这些都依赖于平台并且比纯 Java 解决方案更复杂。

可能值得在 Java 错误数据库中支持相关错误:http ://bugs.sun.com/view_bug.do?bug_id=4770092

运气好的话,我们可以说服 Java 开发人员相信,Java 8 对子进程的不良处理是值得修复的。

于 2011-10-15T11:01:43.813 回答
1

据我所知,commons-exec 中没有这样的选项。甚至不可能获得您刚刚启动的任何进程的 PID。您可以trap在 bash 脚本中发出终止信号,并在脚本进程被终止时让处理程序终止子进程。

于 2011-09-26T10:18:16.607 回答
1

Java 版本 9 以后,Java 提出了可以查询和终止主进程及其后代的功能。查询子进程的代码片段

import java.io.IOException;

public class ProcessTreeTest {
   public static void main(String args[]) throws IOException {
      Runtime.getRuntime().exec("cmd");
     
      System.out.println("Showing children processes:");
      ProcessHandle processHandle = ProcessHandle.current();
      processHandle.children().forEach(childProcess ->
              System.out.println("PID: " + childProcess.pid() + " Command: " + childProcess.info().command().get()));
     
      System.out.println("Showing descendant processes:");
      processHandle.descendants().forEach(descendantProcess ->
              System.out.println("PID: " + descendantProcess.pid() + " Command: " +   descendantProcess.info().command().get()));
   }
}

为了杀死进程及其子进程,Java9 有 API 遍历所有children进程并调用destroy它们中的每一个

例如:在您的情况下,您从 apache-commons 获取 Process 对象,然后尝试以下代码

Process child = ...;
kill (child.toHandle());

public void kill (ProcessHandle handle)
{
    handle.descendants().forEach((child) -> kill(child));
    handle.destroy();
}

参考 :

https://docs.oracle.com/javase/9​​/docs/api/java/lang/ProcessHandle.html

https://www.tutorialspoint.com/how-to-traverse-a-process-tree-of-process-api-in-java-9

如何从 Java 终止进程树?

注意 - 我还没有尝试过这个功能,只是阅读了关于 Java9 并发现在这里分享很有帮助。

于 2021-01-27T07:22:01.507 回答