我正在使用Runtime.getRuntime().exec()
命令启动一个批处理文件,该文件反过来又启动了Windows平台的另一个进程。
javaw.exe(Process1)
|___xyz.bat(Process2)
|___javaw.exe(Process3)
Runtime.getRuntime().exec()
返回一个Process
对象,该对象具有一个destroy方法,但当我使用destroy()
时,它只终止了 xyz.bat,并使批处理文件的子进程悬空。
是否有一种干净的方法来销毁以批处理进程为根的进程树?
为了记录在案,我不能使用任何自定义库来摆脱批处理文件,以绕过这个问题。
6条答案
按热度按时间v64noz0r1#
使用标准的Java API是不可能做到的(请参阅文章末尾的edit,了解对此进行更改的更新)。您将需要一些不同的本地代码。使用JNA时,我使用了如下代码:
}
此代码使用标准JNA库中未包含的以下JNA声明:
然后,您可以使用'getChildren()'方法来取得子系的清单、终止父系,然后递归地终止子系。
我相信您可以使用反射来增加java.lang.Process的PID(不过,我还没有这样做;我转而使用Win32 API自己创建进程,以便对它有更多的控制)。
所以把它放在一起,你需要这样的东西:
编辑
事实证明Java API的这个缺点在Java 9中得到了修复。请参阅Java 9文档here的预览(如果没有加载正确的页面,您需要查看
java.lang.ProcessHandle
接口)。对于上述问题的要求,代码现在看起来如下所示:(Note这还没有经过测试-我还没有转换到Java 9,但是我正在积极地阅读有关它的信息)
yc0p9oo02#
如果您控制子进程和批处理文件,另一种解决方案是让子进程创建一个线程,打开ServerSocket,侦听到它的连接,如果它收到正确的密码,则调用System.exit()。
如果您需要多个并发示例,则可能会出现复杂情况;这时您需要某种方式来为它们分配端口号。
8fsztsew3#
您无法使用标准的Java API for Java 8或更低版本来执行此操作。
方法1
如果您有Java 9或更高版本,则可以使用ProcessHandle
方法二
在Java中,将
taskkill
与/t
配合使用,将/f
标志与Runtime.getRuntime().exec()
或ProcessBuilder
类配合使用。/f --〉强制终止/t --〉终止此进程生成的所有子进程。
详细分析
我已经使用Process Builder在Java代码中完成了它。
下面是一个示例批处理文件,它在Windows中启动另一个
Powershell
进程,每秒从1到20打印计数器,这是一个子进程:ps:您需要将InputStream重定向到stdout以获得终端上的输出。
使用
process
对象的destroy()
方法只终止该进程,而不终止子/孙进程。您可以在终端上运行
tasklist
,然后找到powershell.exe
,在运行java程序之前和之后进行比较,以查看子进程是否仍在运行。要将子进程与父进程沿着删除,请使用
ProcessBuilder
启动一个新进程,如下所示,其中p
是您要删除的进程:hm2xizp94#
你不能使用JDK为窗口删除进程树。你需要依赖WinAPI。你必须求助于本机命令或JNI库,所有这些都是平台相关的,比纯Java解决方案复杂。
示例链接JNI Example
1bqhqjot5#
这里有另一个选择。使用这个powershell脚本来执行你的bat脚本。当你想杀死树时,终止你的powershell脚本的进程,它会自动在它的子进程上执行taskkill。我让它调用taskkill两次,因为在某些情况下它不会接受第一次尝试。
83qze16e6#
在java 9中,杀死主进程会杀死整个进程树。你可以这样做:
请查看此blog并查看***处理流程树***示例。