Существует три Java-приложения, appB просто запускает appC, который будет работать вечно. appA запускает appB и читает его вывод.
Но appA никогда не выходит. У любого есть идея, почему это происходит и как ее решить.
Он не зависает, если я не читаю поток в appA.
Я пробовал два способа:
- Считывание выходного потока (readViaInputStream) или BufferedReader (readViaBufferedReader) напрямую.
Они не работают, результат будет:
// если мы их вызываем, основное приложение зависает, вывод будет:
// Перед вызовом дочернего процесса
// После вызова дочернего процесса
// здесь висит основная программа.
// Никогда не выводить - «Чтение потока завершено».
В readViaInputStream он висит при методе fill () в методе BufferedInputStream.fill () при int n = getInIfOpen (). Read (buffer, pos, buffer.length - pos); Он вызывает собственный метод класса FileInputStream.
То же, что и для метода readViaBufferedReader.
- Используйте другой поток для чтения выходного потока.
Это тоже не работает, вывод будет:
// Перед вызовом дочернего процесса
// После вызова дочернего процесса
// Считывание закончено.
// ===> и основная программа зависает
Большое спасибо за любой ответ:)
Код следующий: обновлен для использования кода Гийома Полета, предоставленного в следующем комментарии.
public class MainApp {
public static enum APP {
B, C;
}
public static void main(String[] args) throws Exception,
InterruptedException {
if (args.length > 0) {
APP app = APP.valueOf(args[0]);
switch (app) {
case B:
performB();
break;
case C:
performC();
break;
}
return;
}
performA();
}
private static void performA() throws Exception {
String javaBin = "java";
String[] cmdArray = { javaBin, "-cp",
System.getProperty("java.class.path"), MainApp.class.getName(),
APP.B.name() };
ProcessBuilder builder = new ProcessBuilder(cmdArray);
builder.redirectErrorStream(true);
final Process process = builder.start();
process.getOutputStream().close();
process.getErrorStream().close();
// if we call this, the main app hangs, the output would be:
// Before call child process
// After call child process
// the main program hangs here.
// Never output - "Read stream finished."
readViaInputStream(process);
// if we call this, the main app hangs, the output would be:
// Before call child process
// After call child process
// the main program hangs here.
// Never output - "Read stream finished."
// readViaBufferedReader(process);
// if we call this, the main app still hangs, the output would be:
// Before call child process
// After call child process
// Read stream finished.
// ===> and the main program hang
// readOutputViaAnotherThread(process);
System.err.println("Read stream finished."); // never come here
}
private static void performB() throws Exception {
System.out.println("Before call child process");
String javaBin = "java";
String[] cmdArray = { javaBin, "-cp",
System.getProperty("java.class.path"), MainApp.class.getName(),
APP.C.name() };
ProcessBuilder builder = new ProcessBuilder(cmdArray);
Process process = builder.start();
process.getInputStream().close();
process.getOutputStream().close();
process.getErrorStream().close();
System.out.println("After call child process");
System.exit(0); // no difference with or without this line.
}
private static void performC() throws Exception {
Thread thread = new Thread() {
@Override
public void run() {
int i = 0;
while (true) {
try {
Thread.sleep(60 * 2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.err.println("child " + ++i);
}
}
};
thread.start();
thread.join();
}
private static void readViaInputStream(final Process process)
throws Exception {
// System.err.println("exitValue: " + process.waitFor());
InputStream is = process.getInputStream();
int result;
while ((result = is.read()) != -1) {
System.err.println(result);
}
}
private static void readViaBufferedReader(final Process process)
throws Exception {
BufferedReader in = new BufferedReader(new InputStreamReader(
process.getInputStream(), "utf-8"));
String result = "";
while ((result = in.readLine()) != null) {
System.err.println(result);
}
}
private static void readOutputViaAnotherThread(final Process process)
throws Exception {
class ReadOutputStreamThread extends Thread {
public void run() {
running = true;
try {
BufferedReader in = new BufferedReader(
new InputStreamReader(process.getInputStream(),
"utf-8"));
String result = "";
while (running && (result = in.readLine()) != null) {
System.err.println(result);
}
} catch (Exception e) {
e.printStackTrace();
}
};
private volatile boolean running;
public void shutdown() throws IOException {
running = false;
// this has no impact
process.getInputStream().close();
interrupt();
}
}
ReadOutputStreamThread readOutputThread = new ReadOutputStreamThread();
// if we set this readOutputThread as daemon, it works, but the thread
// will remains run forever.
// readOutputThread.setDaemon(true);
readOutputThread.start();
System.err.println("exitValue: " + process.waitFor());
readOutputThread.shutdown();
}
}