使用Java,我可以让一个JVM生成另一个JVM,然后让原始的JVM退出吗?

时间:2010-06-09 20:20:28

标签: java process

编辑:似乎我的测试确定原始JVM是否已退出是否有缺陷(请参阅对已接受答案的评论)。对不起噪音。

我需要让正在运行的JVM启动另一个JVM然后退出。我目前正试图通过Runtime.getRuntime().exec()执行此操作。另一个JVM启动,但我的原始JVM将不会退出,直到“子”JVM进程停止。似乎使用Runtime.getRuntime().exec()在进程之间创建父子关系。是否有某种方法可以解除生成的进程以使父进程死亡,或者某种其他机制来生成进程而与创建进程没有任何关系?

请注意,这似乎与此问题完全相同:Using Java to spawn a process and keep it running after parent quits但是那里接受的答案实际上并不起作用,至少在我的系统上是不行的(Windows 7,Java 5和6)。似乎这可能是一个依赖于平台的行为。我正在寻找一种平台独立的方式来可靠地调用其他进程并让我的原始进程死掉。

例如,假设我在C:\myjar.jar有一个jar文件,我想运行该jar中的类com.example.RunMe。假设该类弹出一个JOptionPane,然后在用户点击OK后退出。

现在,以下是在JVM#1中运行的程序:

public static void main(String[] args) {
    String javaHome = System.getProperty("java.home");
    String os = System.getProperty("os.name");
    String javawBin = javaHome + File.separator + "bin" + File.separator + "javaw";

    if (os.toLowerCase().contains("win")) {
        javawBin += ".exe";
    }

    List<String> cmd = new ArrayList<String>();

    cmd.add("\"" + javawBin + "\"");
    cmd.add("-cp");
    cmd.add("\"C:\\myjar.jar\"");
    cmd.add("com.example.RunMe");

    System.out.println("Running: " + cmd);

    try {

        System.out.println("Launching...");
        Process p = Runtime.getRuntime().exec(cmd.toArray(new String[cmd.size()]));

        new Thread(new StreamGobbler(p.getInputStream())).start();
        new Thread(new StreamGobbler(p.getErrorStream())).start();

        System.out.println("Launched JVM.");

        System.exit(0);

    } catch (IOException e) {
        e.printStackTrace();
    }

}

private static class StreamGobbler implements Runnable {
    InputStream stream;

    StreamGobbler(InputStream stream) {
        this.stream = stream;
    }

    public void run() {
        byte[] buf = new byte[64];

        try {
            while (stream.read(buf) != -1)
                ;
        } catch (IOException e) {

        }
    }
}

观察到的行为是“启动......”和“启动JVM”。打印,但JVM#1仅在您通过JVM#2启动的JOptionPane中的OK之后退出。此外 - 无论您是否启动流gobbler线程,行为都是相同的。

另外,为了节省一些人的呼吸,是的,我知道我可以使用该jar文件创建一个新的URLClassLoader并以这种方式运行,但这不是我想要在这里做的。

4 个答案:

答案 0 :(得分:4)

我刚刚尝试了下面的代码,我看到正在生成的进程和主要的进程在Vista和Java 6上。我认为你的代码可能正在发生其他事情。

public class Test {
    public static void main(String[] args) throws Exception {
        if(args.length == 0)
            Runtime.getRuntime().exec("javaw Test loop");
        else
            while(true){}
    }
}

答案 1 :(得分:0)

据我所知,杀死进程通常会杀死所有子进程。我怀疑这是一种独立于平台的方法。

答案 2 :(得分:0)

Windows不会在Unix系统执行的进程之间建立相同类型的父子关系。您的父进程可能没有退出,因为还有一个线程仍然在其中运行。此线程可能正在等待子进程终止,这可以解释为什么您的父进程在子进程退出时会退出。

答案 3 :(得分:0)

运行StreamGobblers的线程在进程#1中,并且不是守护进程线程,因此进程#1在这些线程完成之前不会结束,当流程#2结束时,它们正在吞噬的流程就会消失。

取出创建这些线程的两行。