Java Runtime exec問題
1. java.lang.IllegalThreadStateException: process hasn't exited1 public static void main(String[] args) {
2 try {
3 Process process = Runtime.getRuntime().exec("javac");
4 System.out.println(process.exitValue());
5 } catch (IOException e) {
6 e.printStackTrace();
7 }
8 }
2 try {
3 Process process = Runtime.getRuntime().exec("javac");
4 System.out.println(process.exitValue());
5 } catch (IOException e) {
6 e.printStackTrace();
7 }
8 }
exec方法創建了一個native的進程,并返回該process的對象,如果進程還沒有返回,調用exitValue方法就會出現此異常,因為該方法沒有阻塞,其實現如下:
1 public synchronized int exitValue() {
2 if (!hasExited) {
3 throw new IllegalThreadStateException("process hasn't exited");
4 }
5 return exitcode;
6 }
2 if (!hasExited) {
3 throw new IllegalThreadStateException("process hasn't exited");
4 }
5 return exitcode;
6 }
2. waitFor方法
1 public static void main(String[] args) {
2 try {
3 Process process = Runtime.getRuntime().exec("javac");
4 int result = process.waitFor();
5 System.out.println(result);
6 } catch (IOException e) {
7 e.printStackTrace();
8 } catch (InterruptedException e) {
9 e.printStackTrace();
10 }
11 }
2 try {
3 Process process = Runtime.getRuntime().exec("javac");
4 int result = process.waitFor();
5 System.out.println(result);
6 } catch (IOException e) {
7 e.printStackTrace();
8 } catch (InterruptedException e) {
9 e.printStackTrace();
10 }
11 }
waitFor方法會一直阻塞直到native進程完成,并返回native進程的執行結果。如果native進程無法執行完成,waitFor方法將一直阻塞下去,其實現如下:
1 public synchronized int waitFor() throws InterruptedException {
2 while (!hasExited) {
3 wait();
4 }
5 return exitcode;
6 }
2 while (!hasExited) {
3 wait();
4 }
5 return exitcode;
6 }
該程序在jdk1.7 windows下測試工作正常,返回2; 但是jdk1.4 windows下測試出現hang。JDK documention的解釋是
The methods that create processes may not work well for special processes on certain native platforms,
such as native windowing processes, daemon processes, Win16/DOS processes on Microsoft Windows,or shell scripts.
The created subprocess does not have its own terminal or console. All its standard io (i.e. stdin, stdout, stderr)
operations will be redirected to the parent process through three streams (getOutputStream(), getInputStream(),
getErrorStream()). The parent process uses these streams to feed input to and get output from the subprocess. Because some native platforms only provide limited buffer size for standard input and output streams,
failure to promptly write the input stream or read the output stream of the subprocess may cause
the subprocess to block, and even deadlock.
such as native windowing processes, daemon processes, Win16/DOS processes on Microsoft Windows,or shell scripts.
The created subprocess does not have its own terminal or console. All its standard io (i.e. stdin, stdout, stderr)
operations will be redirected to the parent process through three streams (getOutputStream(), getInputStream(),
getErrorStream()). The parent process uses these streams to feed input to and get output from the subprocess. Because some native platforms only provide limited buffer size for standard input and output streams,
failure to promptly write the input stream or read the output stream of the subprocess may cause
the subprocess to block, and even deadlock.
所以,出現hang時,及時的flush標準輸入輸出或者錯誤流能夠消除hang,如上面的javac,我們知道redirect到stderr中,所以解決hang后的代碼
1 public static void main(String[] args) {
2 try {
3 Process process = Runtime.getRuntime().exec("echo 'abc'>b.txt");
4 BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
5 String line;
6 while((line=reader.readLine())!=null){
7 System.out.println(line);
8 }
9 int result = process.waitFor();
10 System.out.println(result);
11 } catch (IOException e) {
12 e.printStackTrace();
13 } catch (InterruptedException e) {
14 e.printStackTrace();
15 }
16 }
2 try {
3 Process process = Runtime.getRuntime().exec("echo 'abc'>b.txt");
4 BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
5 String line;
6 while((line=reader.readLine())!=null){
7 System.out.println(line);
8 }
9 int result = process.waitFor();
10 System.out.println(result);
11 } catch (IOException e) {
12 e.printStackTrace();
13 } catch (InterruptedException e) {
14 e.printStackTrace();
15 }
16 }
3. exec() is not a command line 并不是所有的command line命令都可以用exec
1 public static void main(String[] args) {
2 try {
3 Process process = Runtime.getRuntime().exec("echo 'abc'>a.txt");
4 BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
5 String line;
6 while((line=reader.readLine())!=null){
7 System.out.println(line);
8 }
9 int result = process.waitFor();
10 System.out.println(result);
11 } catch (IOException e) {
12 e.printStackTrace();
13 } catch (InterruptedException e) {
14 e.printStackTrace();
15 }
16 }
結果為:2 try {
3 Process process = Runtime.getRuntime().exec("echo 'abc'>a.txt");
4 BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
5 String line;
6 while((line=reader.readLine())!=null){
7 System.out.println(line);
8 }
9 int result = process.waitFor();
10 System.out.println(result);
11 } catch (IOException e) {
12 e.printStackTrace();
13 } catch (InterruptedException e) {
14 e.printStackTrace();
15 }
16 }
1 'abc'>a.txt
2 0
并沒有將創建a.txt,而從命令行執行"echo 'abc'>a.txt"卻正確創建了a.txt
2 0