【问题标题】:Killing a process using Java使用 Java 杀死进程
【发布时间】:2011-09-15 10:15:42
【问题描述】:

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

【问题讨论】:

  • java在虚拟机中运行,就像一个封闭的盒子;绝不会在纯 java 中杀死系统进程。可能有调用本机接口的选项。请参阅 JNI 或 JNA
  • 什么技巧解决了您的问题?我也面临同样的问题。我在这里描述了细节:stackoverflow.com/questions/27942679/…
  • @BilalAhmedYaseen 我使用了选定的答案和 Lakshitha Ranasingha 的答案,他们为我做了诀窍。

标签: java process


【解决方案1】:

如果您在 Java 应用程序中从 with 开始进程(例如,通过调用 Runtime.exec()ProcessBuilder.start()),那么您有一个有效的 Process 引用,您可以在 @ 中调用 destroy() 方法987654327@ 类杀死该特定进程。

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

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

【讨论】:

  • 我也面临同样的问题。我在这里描述了细节:stackoverflow.com/questions/27942679/…
  • 请记住,通常情况下,您可能需要管理员权限才能终止进程。也许,您还想在答案中添加 windows 命令来执行此操作。
【解决方案2】:

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
  • 对于 linux ,我使用“pkill firefox”
  • "kill -9" 并不总是一个好主意,因为它不会给被杀死的进程一个干净利落的机会。
  • @JeromeProvensal 如果您正在制作防病毒软件怎么办?你不想让病毒有机会彻底死去!
  • @Holyprogrammer,同意,但我说的不是病毒,而是你控制/理解的过程。
【解决方案3】:

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

taskkill /F /IM <processname>.exe 

要强杀它,你可以使用;

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

【讨论】:

    【解决方案4】:

    这可能是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'
    

    10s 后死亡(未按预期在 1s 后被杀死)并显示:

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

    即使处理了信号,在 Windows 上执行相同操作似乎也可以很好地终止进程(但这可能是由于 Windows 没有使用信号来破坏)。

    其实我发现Java - Process.destroy() source code for Linux相关线程和openjava实现似乎也使用了-TERM,这似乎很错误。

    【讨论】:

    • 使用 -TERM 是正确的,因为它可以让进程自行清理。使用 kill -9 只会破坏可怜的东西。真正正确的方法是使用 kill -TERM,稍等片刻,如果 -9 仍然存在,则将其杀死。
    • 是的 - 但不幸的是 JVM 没有发出以下 kill -9,因此您无法强制杀死。因此仍然是非常错误的。应该有一个强制选项,否则这仅对行为良好的过程有用 - 即仅适用于晴天。
    • 不是destroyForcibly()发送kill -9吗?
    • 确实如此——尽管它仅在 Java 8 中可用(在我正在开发的项目中不可用)。我刚刚注意到 Haysa Rodrigues 已经添加了这个答案。
    【解决方案5】:

    我偶然发现了另一种在 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);
    }
    

    【讨论】:

    • 有一种非hack、跨平台的方式来获取任何JVM应用程序的PID,请查看mostly-about-java.blogspot.co.uk/2013/06/…
    • @Brian Gordon 是的,我知道,使用 sun.jvmstat.monitor.* 也不是一个完美的解决方案,不是受支持的公共接口的一部分,但仍然比依赖外部 unix 更好、更便携工具或期望 Process 是 UNIXProcess,在 Windows 上它不是,也许在未来的 Unix 上的 Java 版本 7 中也不会。
    • @Espinosa 取决于您要实现的目标。 Windows 上的 destroy() 确实强制杀死,所以那里不需要这个 hack(顺便说一句,Weblogic 也有一个适用于 Windows 的类)。请记住,我们必须编写如此丑陋的代码只是因为目光短浅的 JVM 实现和 API 设计缺陷。
    • 继续:最后,这只是品味问题——对于 java 进程管理器,我可能会使用你的解决方案——但为了解决特定的错误,我更喜欢我的更小/更快/更脏的“补丁”而不是你的理论上更清洁但迭代和更麻烦的解决方案。每个钉子都需要不同的锤子。
    【解决方案6】:

    试试看:

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

    如果进程还活着,添加:

    p.destroyForcibly();
    

    【讨论】:

    • 需要注意的是,这仅在 Java 8 上可用。
    • Runtime.exec 返回后,您不知道killall 进程进展到什么程度,然后您立即杀死killall,可能在它有机会做任何事情之前。而不是destroy,你应该waitFor() 它并检查它的退出状态。
    【解决方案7】:

    您可以通过调用 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();
    

    【讨论】:

      【解决方案8】:

      通过Java 9,我们可以使用ProcessHandle,这样更容易识别和控制本机进程:

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

      其中“firefox”是要杀死的进程。

      这个:

      • 首先将系统上运行的所有进程列为Stream&lt;ProcessHandle&gt;

      • 延迟过滤此流以仅保留启动的命令行包含“firefox”的进程。 commandLinecommand 都可以使用,具体取决于我们要如何检索进程。

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

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

      无需导入,因为 ProcessHandlejava.lang 的一部分。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-01-19
        • 1970-01-01
        • 1970-01-01
        • 2016-03-06
        • 1970-01-01
        相关资源
        最近更新 更多