2010-06-09 25 views
9

编辑:看来我的测试,以确定是否原来的JVM已退出有缺陷开始(见接受的答案评论)。对不起,噪音。使用Java,我可以让一个JVM产生另一个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,然后一旦用户点击确定就退出。

现在,以下是在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后才会退出。另外 - 无论您是否启动流式防护线程,行为都是相同的。

此外,为了救一个人的呼吸,是的,我知道我可以创建一个使用该jar文件构造一个新URLClassLoader和运行这样的说法,但那不是我想要在这里做。

+1

您能否提供样品? – OscarRyz 2010-06-09 20:28:39

回答

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){} 
    } 
} 
+0

我认为你是对的。继承人的事情。我检查JVM#1是否退出的晴雨表是否在Eclipse控制台中激活了红色的“停止”按钮,因为这是过去JVM生命的可靠指示器。但是,Windows任务管理器正在向我展示一个不同的故事,即JVM#1会按预期立即退出。那么如何将该eclipse停止按钮绑定到子进程呢? – CarlG 2010-06-09 20:56:35

+0

也许Eclipse不理解System.exit? – ykaganovich 2010-06-09 21:00:41

+0

所有eclipse正在做的是产生javaw.exe本身。它有什么样的链接呢?尽管它从任务管理器中消失,这很奇怪。也许我已经从一座小山上爬了一座山。 – CarlG 2010-06-09 21:08:24

0

据我所知,杀的过程相当频繁杀死所有子进程。我怀疑有一种独立于平台的方式来做到这一点。

+0

2件事情:1)一个过程能产生另一个不是小孩的独立过程吗? 2)我不能杀死父母。 System.exit(0)挂起,直到孩子停止。 – CarlG 2010-06-09 20:24:32

0

Windows不建立同类的是Unix系统做的过程之间的父子关系。很可能您的父进程不在退出,因为还有一个线程仍在运行。此线程可能正在等待子进程终止,这可以解释您的父进程在孩子退出时退出的原因。

+0

父进程挂在System.exit(0)上。这不会抢先等待线程完成吗?另外,这在Win7中仍然如此吗? – CarlG 2010-06-09 20:26:53

+0

@CarlG:挂在'System.exit(0)'中肯定是意外的。我不会想象在Windows 7中进程终止的语义已经发生了变化,但我想他们可以有。我很好奇,看看这个最终的解决方案是什么。 – 2010-06-09 20:29:01

0

你的线程运行StreamGobblers的过程#1中,而不是守护线程,所以进程#1并没有结束,直到那些线程完成,当他们被吞噬消失处理#2结束流。

取出创造那些线程的两条线。

+0

这是我的第一本能,但我会认为System.exit(0)应该照顾正在运行的线程。但是阅读Runtime.exit文档,我想知道如果不同的错误代码会导致不同的行为。 – ykaganovich 2010-06-09 20:53:35

+0

合理,但正如我上面所指出的,拿出那两条线没有任何影响。 – CarlG 2010-06-09 20:54:30

+0

对,对不起。调用'System.exit(0)'处理这些线程。 – 2010-06-09 21:04:21

相关问题