使用 Java,我可以让一个 JVM 生成另一个,然后让原来的 JVM 退出吗?
编辑:看来我确定原始 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
据我所知,杀死一个进程通常会杀死所有子进程。我怀疑是否有一种独立于平台的方法可以做到这一点。
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.
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.
运行 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.
我刚刚尝试了以下代码,我看到进程正在生成,并且主进程在 Vista 和 Java 6 上退出。我认为您的代码可能还存在其他问题。
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.