使用Java杀死进程


71

我想知道如何“杀死”已经启动的过程。我知道Process API,但是不确定,是否可以使用它来杀死已经运行的进程,例如firefox.exe等。如果可以使用Process API,请您指向我正确的方向?如果没有,还有哪些其他可用选项?谢谢。


java在虚拟机中运行,就像一个封闭的盒子。绝不是用纯Java杀死系统进程。可能有调用本机接口的选项。参见JNI或JNA
数字幻觉

什么技巧解决了您的问题?我也面临着同样的问题。我在这里已描述了详细信息:stackoverflow.com/questions/27942679/…–
比拉勒·艾哈迈德·亚辛

1
@BilalAhmedYaseen我使用了选定的答案以及Lakshitha Ranasingha的答案,他们为我做了窍门。
谢尔·沙

Answers:


58

如果您是从Java应用程序中以从头开始的过程(例如,通过调用Runtime.exec()ProcessBuilder.start()),那么您将对其具有有效的Process引用,并且可以destroy()Process类中调用该方法以终止该特定过程。

但是请注意,如果您调用的流程创建了新的子流程,则这些子流程可能不会终止(请参见http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4770092)。

另一方面,如果您想杀死外部进程(您不是从Java应用程序生成的),那么您可以做的一件事就是调用允许您执行此操作的O / S实用程序。例如,您可以尝试在Unix / Linux下使用Runtime.exec()onkill命令并检查返回值,以确保应用程序是否被杀死(0表示成功,-1表示错误)。但这当然会使您的应用程序平台依赖。


我也面临着同样的问题。我在这里描述了详细信息:stackoverflow.com/questions/27942679/…–
比拉勒·艾哈迈德·亚辛

请记住,通常,您可能需要管理员权限才能杀死进程。也许,您还想在答案中添加Windows命令来执行此操作。
PhoneixS

61

在Windows上,您可以使用此命令。

taskkill /F /IM <processname>.exe 

要强行杀死它,您可以使用;

Runtime.getRuntime().exec("taskkill /F /IM <processname>.exe")

32

AFAIU java.lang.Process是由Java本身创建的进程(例如Runtime.exec('firefox'))

您可以使用与系统有关的命令,例如

 Runtime rt = Runtime.getRuntime();
  if (System.getProperty("os.name").toLowerCase().indexOf("windows") > -1) 
     rt.exec("taskkill " +....);
   else
     rt.exec("kill -9 " +....);

适用于Win7 64位:D
Broken_Window 2015年

8
对于Linux,我使用了“ pkill firefox”
Rajendra Thorat 2015年

2
“ kill -9”并不总是一个好主意,因为它不会给被杀死的进程提供彻底清除的机会。
Jerome Provensal

@JeromeProvensal如果要制作防病毒软件该怎么办?你希望给病毒有机会干净下来!
Khushraj Rathod

1
@Holyprogrammer,同意,但是我不是在谈论病毒,而是您可以控制/理解的过程。
Jerome Provensal,

10

使用Java 9,我们可以使用ProcessHandle,它使识别和控制本机进程变得更加容易:

ProcessHandle
  .allProcesses()
  .filter(p -> p.info().commandLine().map(c -> c.contains("firefox")).orElse(false))
  .findFirst()
  .ifPresent(ProcessHandle::destroy)

其中“ firefox”是杀死进程。

这个:

  • 首先将所有在系统上运行的进程列为 Stream<ProcessHandle>

  • 延迟过滤此流,以仅保留其启动的命令行包含“ firefox”的进程。根据我们想要检索该过程的方式,可以使用commandLine或两者command

  • 查找满足过滤条件的第一个过滤过程。

  • 并且如果至少一个进程的命令行包含“ firefox”,则使用杀死它destroy

不需要导入,这ProcessHandle是的一部分java.lang


4

偶然地,我偶然发现了另一种在Unix上强行杀死他人的方法(对于那些使用Weblogic的人)。这比通过Runtime.exec()运行/ bin / kill -9更便宜,也更优雅。

import weblogic.nodemanager.util.Platform;
import weblogic.nodemanager.util.ProcessControl;
...
ProcessControl pctl = Platform.getProcessControl();
pctl.killProcess(pid);

而且,如果您难以获得pid,则可以在java.lang.UNIXProcess上使用反射,例如:

Process proc = Runtime.getRuntime().exec(cmdarray, envp);
if (proc instanceof UNIXProcess) {
    Field f = proc.getClass().getDeclaredField("pid");
    f.setAccessible(true);
    int pid = f.get(proc);
}

有一种非黑客的,跨平台的方法,如何为任何JVM应用程序获取PID,请检查大部分-about-java.blogspot.co.uk/2013/06/…–
Espinosa

@Brian Gordon是的,我知道,使用sun.jvmstat.monitor。*也不是一个完美的解决方案,它不是受支持的公共接口的一部分,但是仍然更好且可移植,因此它依赖于外部unix工具或期望Process为UNIXProcess,在Windows上不是,将来在Unix上的Java第七版中也可能不会。
Espinosa

@Espinosa取决于您要实现的目标。Windows上的destroy()确实会强制执行终止操作,因此在那里不需要此技巧(btw Weblogic的确也有Windows类)。请记住,仅由于短视的JVM实现和API设计缺陷,我们才必须编写此类丑陋的代码。
chukko 2015年

继续:最终只是口味问题-对于Java进程管理器,我可能会使用您的解决方案-但要解决特定的错误,我更喜欢我的较小/更快/较脏的“补丁”,而不是理论上更干净但迭代且更麻烦的解决方案。每个钉子需要使用不同的锤子。
chukko 2015年

3

这可能是Java解释器缺陷,但是HPUX上的Java不会执行kill -9,而只能执行kill -TERM。

我做了一个小测试testDestroy.java:

ProcessBuilder pb = new ProcessBuilder(args);
Process process = pb.start();
Thread.sleep(1000);
process.destroy();
process.waitFor();

和调用:

$ tusc -f -p -s signal,kill -e /opt/java1.5/bin/java testDestroy sh -c 'trap "echo TERM" TERM; sleep 10'

10秒后死亡(未如预期的1秒后死亡)并显示:

...
[19999]   Received signal 15, SIGTERM, in waitpid(), [caught], no siginfo
[19998] kill(19999, SIGTERM) ............................................................................. = 0
...

即使在处理信号的情况下,在Windows上执行相同的操作似乎也可以杀死进程(但这可能是由于Windows未使用信号来销毁)。

实际上,我发现Linux相关线程的Java-Process.destroy()源代码和openjava实现似乎也都使用-TERM,这似乎非常错误。


1
使用-TERM是正确的,因为它可以使进程在执行后自行清理。使用kill -9只会破坏可怜的东西。真正正确的方法是使用kill -TERM,等待一段时间,然后在仍然存在的情况下杀死-9。
Urban Vagabond 2014年

1
是的-但不幸的是,JVM不会发出以下kill -9,因此您无法强制执行kill。因此仍然是非常错误的。应该有一个强制选项,否则仅对行为良好的过程(即仅在晴天)有用。
chukko 2014年

1
destroyForcibly()发送kill -9吗?
OndraŽižka'17

确实的确如此-尽管它仅在Java 8中可用(我正在为其开发的项目中没有此功能)。我只是注意到Haysa Rodrigues已经添加了该答案。
chukko

3

试试看:

String command = "killall <your_proccess>";
Process p = Runtime.getRuntime().exec(command);
p.destroy();

如果该过程仍然存在,请添加:

p.destroyForcibly();

需要注意的是,这仅在Java 8上可用
。– chukko

之后Runtime.exec又回来了,你不知道多远killall进程已取得进展,然后立即杀死killall,也许收到了做任何事情的机会。而不是destroy,您应该选择waitFor()它并检查其退出状态。
EndlosSchleife

1

您可以通过调用Process对象上的destroy方法来杀死(SIGTERM)从Java启动的Windows进程。您也可以杀死任何子进程(自Java 9开始)。

以下代码启动一个批处理文件,等待十秒钟,然后终止所有子进程,最后终止该批处理进程本身。

ProcessBuilder pb = new ProcessBuilder("cmd /c my_script.bat"));
Process p = pb.start();
p.waitFor(10, TimeUnit.SECONDS);

p.descendants().forEach(ph -> {
    ph.destroy();
});

p.destroy();
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.