Java ProcessBuilder: Результирующий Процесс Зависает
Я пытался использовать ProcessBuilder Java для запуска приложения в Linux, которое должно работать "долгосрочно". Способ запуска этой программы-запустить команду (в этом случае я запускаю приложение воспроизведения мультимедиа), разрешить ей запуск и проверить, не разбился ли она. Например, проверьте, активен ли PID, а затем перезапустите процесс, если он умер.
проблема, которую я получаю прямо сейчас, заключается в том, что PID остается живым в системе, но GUI для приложение зависает. Я попытался переместить ProcessBuilder (cmd).start () в отдельный поток, но это, похоже, ничего не решает, как я надеялся.
в основном результат заключается в том, что для пользователя программа, похоже, разбилась, но убивает процесс Java, который управляет ProcessBuilder.процесс start () фактически позволяет созданному процессу возобновить свое нормальное поведение. Это означает, что что-то в приложении Java вмешивается в порожденный процесс, но я понятия не имею, что на данный момент. (Поэтому я попытался разделить его на другой поток, который, похоже, ничего не решил)
Если у кого-то есть какие-либо вход/мысли, пожалуйста, дайте мне знать, так как я не могу для жизни меня думать о том, как решить эту проблему.
Edit: я не беспокоюсь о потоке ввода-вывода, созданном из процесса, и, таким образом, не предпринял никаких шагов, чтобы справиться с этим-может ли это вызвать зависание в самом процессе?
8 ответов
Если процесс пишет в stderr или stdout, и вы его не читаете - он просто "зависнет" , блокируя при записи в stdout/err. Либо перенаправить stdout / err в /dev/null с помощью оболочки, либо объединить stdout / err с redirectErrorStream(true) и создать другой поток, который читает из stdout процесса
вы хотите на трюк?
Не начинайте процесс с ProcessBuilder.start (). Не пытайтесь возиться с перенаправлением/потреблением потока с Java (особенно если вы не даете об этом никакого s**t ; )
использовать ProcessBuilder.start () чтобы запустить небольшой скрипт оболочки, который поглощает все входные / выходные потоки.
что-то вроде этого:
#!/bin/bash
nohup >/dev/null 2>error.log &
то есть: если вы не заботитесь о stdout и еще хочу журнал stderr (do you?) в файл (ошибка.log здесь).
Если вы даже не заботитесь о stderr, просто перенаправьте его на stdout:
#!/bin/bash
nohup >/dev/null 2>1 &
и вы вызываете этот крошечный скрипт из Java, давая ему в качестве аргумента имя процесса, который вы хотите запустить.
Если процесс, запущенный в Linux, который перенаправляет stdout и stderr в /dev / null, все еще производит что-нибудь тогда у вас есть сломанная, несовместимая установка Linux ;)
другими словами: выше просто работает [TM] и избавляется от проблемного "вам нужно потреблять потоки в этом и том порядке бла-бла-бла Java-специфический не-смысл".
поток, выполняющий процесс, может блокировать, если он не обрабатывает выходные данные. Это можно сделать, создав новый поток, который считывает выходные данные процесса.
final ProcessBuilder builder = new ProcessBuilder("script")
.redirectErrorStream(true)
.directory(workDirectory);
final Process process = builder.start();
final StringWriter writer = new StringWriter();
new Thread(new Runnable() {
public void run() {
IOUtils.copy(process.getInputStream(), writer);
}
}).start();
final int exitValue = process.waitFor();
final String processOutput = writer.toString();
просто наткнулся на это после того, как у меня была аналогичная проблема. Соглашаясь с nos, вам нужно обрабатывать выход. У меня было что-то вроде этого:
ProcessBuilder myProc2 = new ProcessBuilder(command);
final Process process = myProc2.start();
и он работал отлично. Порожденный процесс даже сделал вывод некоторые выход, но не сильно. Когда я начал выводить намного больше, оказалось, что мой процесс даже не запускается больше. Я обновил это:
ProcessBuilder myProc2 = new ProcessBuilder(command);
myProc2.redirectErrorStream(true);
final Process process = myProc2.start();
InputStream myIS = process.getInputStream();
String tempOut = convertStreamToStr(myIS);
и он снова начал работать. (см. эту ссылку для кода convertStreamToStr (): http://singztechmusings.wordpress.com/2011/06/21/getting-started-with-javas-processbuilder-a-sample-utility-class-to-interact-with-linux-from-java-program/)
Edit: я не имею никакого отношения к потоку ввода-вывода, созданному из процесса, и, таким образом, не предпринял никаких шагов, чтобы справиться с этим-может ли это вызвать зависание в самом процессе?
Если вы не читаете выходные потоки, созданные процессом, то возможно, что приложение заблокирует, как только буферы приложения будут заполнены. Я никогда не видел, чтобы это происходило в Linux (хотя я не говорю, что это не так), но я видел эту точную проблему в Windows. Я думаю, это, вероятно, связано.
JDK7 будет иметь встроенную поддержку для перенаправления ввода-вывода подпроцесса:
http://download.oracle.com/javase/7/docs/api/java/lang/ProcessBuilder.html
тем временем, если вы действительно хотите отказаться от stdout / stderr, лучше всего (в Linux) вызвать ProcessBuilder по команде, которая выглядит так:
["/bin/bash", "-c", "exec YOUR_COMMAND_HERE >/dev/null 2>&1"]
в случае, если вам нужно захватить stdout и stderr и контролировать процесс, то с помощью Apache Commons Exec мне очень помогли.
Я считаю, что проблема заключается в буферизации канала от самого Linux.
попробуйте использовать stdbuf
с исполняемым файлом
new ProcessBuilder().command("/usr/bin/stdbuf","-o0","*executable*","*arguments*");**
на -o0
говорит не буферизировать вывод.
То же самое относится к -i0
и -e0
если вы хотите unbuffer входной сигнал и труба ошибки.