-
Bug
-
Resolution: Not an Issue
-
P4
-
None
-
1.3.0, 1.3.0_02, 1.3.1
-
x86
-
linux
Name: boT120536 Date: 03/06/2001
java version "1.3.1-beta"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.1-beta-b15)
Java HotSpot(TM) Client VM (build 1.3.1beta-b15, mixed mode)
Starting an external process using Runtime.exec() and trying to get the text written to stdout or stderr does not always work.
In order to reproduce the problem try to compile and run the following test program using the following short sh-script for echo_cmd:
#!/bin/sh
echo Hello
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.io.IOException;
public class ExecProblem {
private StreamReaderThread outReaderThread;
private StreamReaderThread errReaderThread;
private int num;
public ExecProblem(int num) {
this.num = num;
outReaderThread = new StreamReaderThread();
errReaderThread = new StreamReaderThread();
}
public void execute() {
int retVal;
Runtime rt = Runtime.getRuntime();
try {
// Start threads storing the output of the macro
outReaderThread.start();
errReaderThread.start();
// Start external process
Process proc = rt.exec("/bin/sh ./echo_cmd");
//Thread.sleep(1000);
// Set input streams and wakeup reader threads
outReaderThread.setInputStream(proc.getInputStream());
errReaderThread.setInputStream(proc.getErrorStream());
// Wait for macro termination
retVal = proc.waitFor();
// Close streams (necessary ?)
proc.getInputStream().close();
proc.getErrorStream().close();
proc.getOutputStream().close();
} catch (IOException ex) {
} catch (InterruptedException ex) {
}
// Print result
System.out.println(num+": Out = "+outReaderThread.getText());
System.out.println(num+": Err = "+errReaderThread.getText());
}
private class StreamReaderThread extends Thread {
private BufferedReader br;
private StringBuffer sb;
private String newline;
private String line;
public StreamReaderThread() {
br = null;
sb = null;
newline = null;
line = null;
}
public synchronized String getText() {
if (sb == null) return "";
return sb.toString();
}
public synchronized void setInputStream(InputStream is) {
br = new BufferedReader(new InputStreamReader(is));
notify();
}
public synchronized void run() {
try {
wait();
while ((line = br.readLine()) != null) {
if (sb == null) {
sb = new StringBuffer();
newline = System.getProperty("line.separator");
} else {
sb.append(newline);
}
sb.append(line);
}
} catch (IOException ex) {
} catch (InterruptedException ex) {
}
}
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
ExecProblem execProblem = new ExecProblem(i);
execProblem.execute();
}
}
}
Running the program with "java ExecProblem" will produce an output like the following:
0: Out = Hello
0: Err =
1: Out = Hello
1: Err =
2: Out = Hello
2: Err =
3: Out = Hello
3: Err =
4: Out =
4: Err =
5: Out = Hello
5: Err =
6: Out = Hello
6: Err =
7: Out = Hello
7: Err =
8: Out = Hello
8: Err =
9: Out =
9: Err =
As you can see, not every execution of the sh-script produces the desired output. Things get worst if you uncomment the line Thread.sleep(1000);
This will produce an additional delay between starting the external process and
getting the streams.
The resulting output is:
0: Out =
0: Err =
1: Out =
1: Err =
2: Out =
2: Err =
3: Out =
3: Err =
4: Out =
4: Err =
5: Out =
5: Err =
6: Out =
6: Err =
7: Out =
7: Err =
8: Out =
8: Err =
9: Out =
9: Err =
The problem seams to be, that if the time difference between calling
rt.exec("..."); and obtaining the input- and errorstreams is longer than the time the external process needs to complete the text written by the external process gets lost. This observation leads to my rather "difficult" solution for the StreamReaderThread class using wait() and notify() because I wanted to make the time between rt.exec() and reading from the streams as short as possible.
I also tried the "solution" described in http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html
which does not use wait() and notify() but creates the reader threads after
the call to rt.exec() providing the streams from process.getInputStream() and process.getErrorStream() in the threads constructors. This needs more time than my solution and for that reason does not work too.
If my conclusions are correct a possible solution could be, that the caller of Runtime.exec() provides the streams for stdout/stderr in order to be connected to the external process in the exec() method.
(Review ID: 117998)
======================================================================
- duplicates
-
JDK-4458073 io from Process does not work from other threads
- Closed