【问题标题】:"Kill a process tree" on windows using Java使用 Java 在 Windows 上“杀死进程树”
【发布时间】:2011-09-26 03:27:58
【问题描述】:

我有一个 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 在 c++ 中执行等效任务。我想知道是否有人实现了通过 JNI 调用 Windows 本机系统调用。

【问题讨论】:

  • 对这个问题做了一些背景调查。在 Process.destroy() 方法中无法杀死子进程。 Linkwindows上任何解决这个问题的方法都应该是调用原生库来实现的。

标签: java apache-commons-exec


【解决方案1】:

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

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

这里是link,用于从 java.lang.Process 获取 Windows 进程 ID。这使用 JNA 库。

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

【讨论】:

    【解决方案2】:

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

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

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

    【讨论】:

      【解决方案3】:

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

      【讨论】:

      • 不幸的是,这些脚本是一个 windows .bat 脚本。所以我不确定windows脚本中是否提供了一种机制来捕获kill命令
      【解决方案4】:

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

      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

      How do i terminate a process tree from Java?

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-06-08
        • 1970-01-01
        • 2011-09-15
        • 2019-07-09
        • 1970-01-01
        • 2012-06-13
        相关资源
        最近更新 更多