Подтвердить что ты не робот

Process.waitFor(), потоки и InputStreams

В псевдокоде, вот что я делаю:

Process proc = runtime.exec(command);
processOutputStreamInThread(proc.getInputStream());
processOutputStreamInThread(proc.getErrorStream());
proc.waitFor()

Однако иногда processOutputStreamInThread не видит никакого вывода, а иногда и делает. Примерно, метод создает BufferedInputStream выход команды и отправляет его в журнал.

Основываясь на том, что я вижу, я предполагаю, что command не обязательно иметь все, что он выводит, в потоки, подаваемые getInputStream() и getErrorStream(), что позволяет потоку быть пустым.

Результаты моих испытаний следующие вопросы:

(1). waitFor() в java.lang.Process требует, чтобы исполняемый выход программы имел был прочитан, прежде чем он вернется?

В документации указано только:

заставляет текущий поток ждать, если необходимо, до тех пор, пока процесс, представленный этим объектом Process, не будет завершен. Этот метод немедленно возвращается, если подпроцесс уже завершен. Если подпроцесс еще не завершен, вызывающий поток будет заблокирован до завершения подпроцесса.

(2) При каких условиях потоки, предоставляемые getInputStream и getErrorStream, должны быть закрыты и/или автоматически закрыты?

В документации указано только:

Получает поток ошибок подпроцесса. Поток получает данные, передаваемые по потоку потока ошибок процесса, представленного этим объектом Process.

Замечание по внедрению. Хорошая идея для буферизации входного потока.

Один пользовательский отчет, который он должен был закрыть самими потоками, но я получаю исключение, по крайней мере, часть времени, указывающего, что поток уже закрыт, когда я пытаюсь для этого.

Изменить: изменено getOutputStream на getInputStream, которое представлено выше.

Разрешение: Проблема заключалась в том, что в некоторых случаях потоки, используемые для обработки выходного потока, не выполнялись до тех пор, пока мой очень короткий срок не завершился, в результате чего поток ввода мне нет данных. waitFor не ожидал вывода исполняемой программы. Скорее, программа запускалась и завершалась до того, как любой результат мог быть собран.

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

Мой окончательный код выглядел примерно так:

ProcessBuilder pb = new ProcessBuilder(cmdargs);
pb.redirectErrorStream(true);
Process proc = pb.start();
processOutputStream(proc.getInputStream());
proc.waitFor()
4b9b3361

Ответ 1

Если ваш внешний процесс ожидает что-то на своем stdin, вы ДОЛЖНЫ закрыть getOutputStream. В противном случае вы будете waitFor навсегда.

Вот Когда Runtime.exec() не станет статьей из JavaWorld, которая описывает различные ошибки метода exec и как их избежать.

Из моего опыта лучше использовать STDOUT и STDERR дочернего процесса (до тех пор, пока они не будут EOF), а затем заблокировать в waitFor. Надеюсь, в этот момент вам не придется долго ждать.

Ответ на вопрос Калеба. В нормальных условиях вы не должны закрывать потоки, однако, поскольку вы waitingFor и по какой-то причине у него нет тайм-аута, вам может понадобиться закрыть эти потоки, если вы столкнетесь с некоторыми условиями ошибки на выходе и не хотите для дальнейшей обработки выходных данных. Однако, будет ли дочерняя программа завершена (сбой), когда STDOUT или STDERR-канал закрыт на другом конце, полностью зависит от реализации этого дочернего элемента. Однако большинство программ оболочки будут прекращены в таких условиях.

Я действительно желаю, чтобы waitFor имел какой-то значимый тайм-аут, хотя и Process имел документированный способ очистки своих ресурсов, когда вы решили отказаться от его мониторинга.

Ответ 2

Я думаю, что это немного противоречит интуиции, но:

getOutputStream Получает вывод поток подпроцесса. Вывод на поток подается в стандартный входной поток процесса представленный этим объектом Process. Замечание по реализации: это хорошая идея для буферизации выходного потока. Возвращает: подключенный выходной поток к нормальному входу подпроцесса.

Я прочитал это как этот выходной поток из основного процесса и подключен к стандартным входам подпроцесса, поэтому, когда вы пишете getOutputStream(). write(), вы на самом деле записываете на stdin.

Возможно, вы хотите использовать .getInputStream()?

Возвращает:     входной поток, подключенный к нормальному выходу подпроцесса.

Что касается Process.Waitfor(), документы API говорят:

заставляет текущий поток ждать, если необходимо, пока процесс представленный этим объектом процесса, имеет прекращается. Этот метод возвращает немедленно, если подпроцесс имеет уже прекращено. Если подпроцесс еще не прекращено, поток будет заблокирован до тех пор, пока выходы подпроцесса.

Я бы сказал, что поток, который вызывается, будет заблокирован до тех пор, пока процесс не завершит выполнение - вы все равно можете обрабатывать выходные данные на этом этапе в зависимости от других потоков или они могут быть закончены до того, как ваш поток вернется.