用于强制终止子进程的Java工具/方法

时间:2011-02-06 08:10:01

标签: java process kill

我正在寻找一个允许我强行杀死的Java工具/包/库 一个孩子的过程。

此工具/包/库必须在Windows平台上运行(必需)。 需要支持Linux / Unix。

我的问题

我的Java代码创建了一个不会对其做出反应的子进程 杀死子进程的标准Java方法:process.destroy(),和 因为我没有孩子的源代码,所以我无法编程 更好地处理终止请求。

我试过关闭子进程的错误输入和输出流 在调用destroy()之前,没有效果。

我甚至尝试将ctrlBreak信号(char = 3)直接传入 child.getOutputStream(),并再次收到相同的结果。

我最终找到的解决方法是:

  1. 创建孩子的PID     这可以通过区分进程列表在Windows中完成     在孩子创作之前和之后(getRuntime().exec("tasklist /v")

  2. 使用子PID发出强制终止系统命令
            在Windows中:getRuntime().exec("taskkill /pid " + childPid + " /f")

  3. 但是 - 这是复杂的代码,我不想调试和维护,加上问题 我毫不怀疑,以前遇到过许多其他java开发人员, 这让我希望这样的Java工具/包/库已经存在。

    我只是不知道它的名字......

    PS:我的子进程是由Runtime.getRuntime().exec(cmd)创建的,但是 我使用ProcessBuilder获得相同的行为。

3 个答案:

答案 0 :(得分:8)

使用Java JNA有一种更精简的方法。

这适用于Windows和Linux,我假设你也可以为其他平台做同样的事情。

Java进程处理的最大问题是缺少一种方法来获取使用untime.getRuntime()。exec()启动进程的进程ID。

假设你有一个进程的pid,你总是可以在linux中启动kill -9命令,或者使用类似的方法来杀死windows中的进程。

这是一种为linux本身获取进程id的方法(借用selenium框架,:)),在JNA的帮助下,这也可以用于windows(使用本机Windows API调用)。

要使其正常工作(对于Windows),首先必须在JAVA NATIVE ACCESS (JNA): Downloads获取JNA库,或者从maven获取

看看下面的代码,它将得到一个(在这个例子中为windows)程序的pid(大多数代码实际上是碎片以获得正常工作的java程序):

import com.sun.jna.*;
import java.lang.reflect.Field;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Main {

static interface Kernel32 extends Library {

    public static Kernel32 INSTANCE = (Kernel32) Native.loadLibrary("kernel32", Kernel32.class);

    public int GetProcessId(Long hProcess);
}

public static void main(String[] args) {
    try {
        Process p;

        if (Platform.isWindows())
            p = Runtime.getRuntime().exec("cmd /C ping msn.de");
        else if (Platform.isLinux())
            p = Runtime.getRuntime().exec("cmd /C ping msn.de");

        System.out.println("The PID: " + getPid(p));

        int x = p.waitFor();
        System.out.println("Exit with exitcode: " + x);

    } catch (Exception ex) {
        Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
    }
}

public static int getPid(Process p) {
    Field f;

    if (Platform.isWindows()) {
        try {
            f = p.getClass().getDeclaredField("handle");
            f.setAccessible(true);
            int pid = Kernel32.INSTANCE.GetProcessId((Long) f.get(p));
            return pid;
        } catch (Exception ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        }
    } else if (Platform.isLinux()) {
        try {
            f = p.getClass().getDeclaredField("pid");
            f.setAccessible(true);
            int pid = (Integer) f.get(p);
            return pid;
        } catch (Exception ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    else{}
    return 0;
}
}

希望这会有所帮助,;)......

答案 1 :(得分:2)

我在过去使用你在这里建议的相同方法解决了这个问题:使用taskkill for windows和kill -9 for Unix。

在Windows上,您可以通过从Java调用脚本(VBS或JS)或使用互操作性库(JaWin,Jintegra,Jinterop等)之一来使用WMI。

我认为这种解决方案并不像你害怕那么复杂。我认为它不超过50个代码行。

祝你好运。

答案 2 :(得分:1)

对于使用jna 3.5.1的Windows

try {
        Process p = Runtime.getRuntime.exec("notepad");

        Field f = p.getClass().getDeclaredField("handle");
        f.setAccessible(true);              
        long handLong = f.getLong(p);

            Kernel32 kernel = Kernel32.INSTANCE;

        WinNT.HANDLE handle = new WinNT.HANDLE();

        handle.setPointer(Pointer.createConstant(handLong));

        int pid = kernel.GetProcessId(handle);

        System.out.print(pid);
    } catch (Throwable e) {
}