Используя Java, могу ли я создать одну JVM, порождать другую, а затем получить исходный выход? - PullRequest
12 голосов
/ 10 июня 2010

Редактировать: Мне кажется, что мой тест для определения того, был ли исходный выход JVM, был некорректным для начала (см. Комментарии к принятому ответу). Извините за шум.

У меня естьнеобходимо, чтобы запущенная JVM запустила другую JVM и затем вышла.В настоящее время я пытаюсь сделать это через Runtime.getRuntime().exec().Запускается другая JVM, но моя исходная JVM не завершится, пока не остановится «дочерний» процесс JVM.Похоже, что использование Runtime.getRuntime().exec() создает отношения родитель-потомок между процессами.Есть ли какой-нибудь способ отсоединить порожденный процесс, чтобы родитель мог умереть, или какой-то другой механизм, чтобы порождать процесс без какого-либо отношения к процессу создания?

Обратите внимание, что это выглядит в точности как этот вопрос: Использование Java для порождения процесса и продолжения его работы после выхода из родительского процесса , но принятый там ответ на самом деле не работает, по крайней мере, в моей системе (Windows 7, Java 5 и 6).Похоже, что это может зависеть от платформы.Я ищу платформу независимый способ надежно вызвать другой процесс и позволить моему исходному процессу умереть.

Например, предположим, у меня есть файл jar на C:\myjar.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 завершается только после того, как вы нажмете OK в JOptionPane, запущенной JVM # 2.Кроме того, поведение одинаково, независимо от того, запускаете ли вы потоки гоблеров потока или нет.

Кроме того, чтобы сохранить кому-то дыхание, да, я знаю, что мог бы создать новый URLClassLoader с этим файлом JAR и запустить еготаким образом, но это не то, что я пытаюсь сделать здесь.

Ответы [ 4 ]

4 голосов
/ 10 июня 2010

Я только что попробовал следующий код, и я вижу, что процессы запускаются и основной из них выходит в 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 голосов
/ 10 июня 2010

Ваши потоки, работающие StreamGobblers, находятся внутри Процесса № 1 и не являются потоками демона, поэтому Процесс № 1 не завершается до тех пор, пока эти потоки не завершатся, когда потоки, которые они поглощают, уходят по мере завершения Процесса № 2.

Уберите две строки, которые создают эти темы.

0 голосов
/ 10 июня 2010

Windows не устанавливает тот же тип родительско-дочерних отношений между процессами, что и системы Unix.Вероятно, ваш родительский процесс не завершается, потому что в нем все еще работает поток.Этот поток может ожидать завершения дочернего процесса, что может объяснить, почему ваш родитель завершает работу, когда выходит дочерний процесс.

0 голосов
/ 10 июня 2010

Насколько я знаю, убийство процесса довольно часто убивает все дочерние процессы. Я сомневаюсь, что есть независимый от платформы способ сделать это.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...