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

发布于 2024-09-05 04:36:41 字数 2297 浏览 5 评论 0原文

编辑:看来我确定原始 JVM 是否已退出的测试一开始就有缺陷(请参阅对已接受答案的评论)。 抱歉产生噪音。

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

请注意,这看起来完全像这个问题: 使用 Java 生成一个进程并在父进程退出后保持其运行,但接受的答案实际上不起作用,至少在我的系统上不起作用(Windows 7、Java 5 和 6)。看来这也许是一种依赖于平台的行为。我正在寻找一种独立于平台的方法来可靠地调用其他进程并让我的原始进程终止。

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

现在,以下是在 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 中单击“确定”后才退出。另外 - 无论您是否启动流 gobbler 线程,行为都是相同的。

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

Edit: It seems my test to determine whether the original JVM had exited was flawed to begin with (see comments on accepted answer). Sorry for the noise.

I have a need to have a running JVM start another JVM and then exit. I'm currently trying to do this via Runtime.getRuntime().exec(). The other JVM starts, but my original JVM won't exit until the "child" JVM process stops. It appears that using Runtime.getRuntime().exec() creates a parent-child relationship between the processes. Is there some way to de-couple the spawned process so that the parent can die, or some other mechanism to spawn a process without any relationship to the creating process?

Note that this seems exactly like this question: Using Java to spawn a process and keep it running after parent quits but the accepted answer there doesn't actually work, at least not on my system (Windows 7, Java 5 and 6). It seems that maybe this is a platform-dependent behavior. I'm looking for a platform independent way to reliably invoke the other process and let my original process die.

For example, suppose I have a jar file at C:\myjar.jar and I want to run the class com.example.RunMe that lives in that jar. Lets say that class pops up a JOptionPane, and then exits once the user has hit OK.

Now, the following is the program running in 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) {

        }
    }
}

The observed behavior is that both "Launching..." and "Launched JVM." are printed, but JVM #1 only exits after you hit OK in the JOptionPane launched by JVM #2. Also - the behavior is the same whether or not you start up the stream gobbler threads or not.

Also, to save someone the breath, yes I know I could create a new URLClassLoader with that jar file and run it that way, but thats not what I'm trying to do here.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

染墨丶若流云 2024-09-12 04:36:42

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

As far as I know, killing a process fairly often kills all child processes. I doubt there's a platform independent way to do this.

旧人哭 2024-09-12 04:36:42

Windows 并不像 Unix 系统那样在进程之间建立同样类型的父子关系。您的父进程很可能没有退出,因为其中仍有一个线程正在运行。该线程可能正在等待子进程终止,这可以解释为什么当子进程退出时父进程也退出。

Windows doesn't establish the same kind of parent-child relationship between processes that Unix systems do. It is likely that your parent process isn't exiting because there's a thread still running in it. This thread may be waiting for the child process to terminate, which could explain why your parent exits when the child exits.

冷情妓 2024-09-12 04:36:42

运行 StreamGobblers 的线程位于 Process #1 内,并且不是守护线程,因此 Process #1 不会结束,直到这些线程完成,当它们正在吞噬的 Streams 随着 Process #2 结束而消失时。

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

Your threads running StreamGobblers are within Process #1, and are not daemon threads, so Process #1 doesn't end till those threads complete, when the Streams they are gobbling go away as Process #2 ends.

Take out the two lines that create those threads.

凉月流沐 2024-09-12 04:36:41

我刚刚尝试了以下代码,我看到进程正在生成,并且主进程在 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){}
    }
}

I just tried the following code, and I see processes being spawned and main one exiting on Vista and Java 6. I think something else might be going on with your code.

public class Test {
    public static void main(String[] args) throws Exception {
        if(args.length == 0)
            Runtime.getRuntime().exec("javaw Test loop");
        else
            while(true){}
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文