记一次使用 Process 对象时遇到的问题

Java中提供一个Runtime.exec()方法,可以用来生成一个Process对象,然后在这个Process对象中执行脚本。

但今天发现执行后,一直没有输出,同时也没有报错,没有Process结束的迹象。

自行搜索后发现原因如下源自该网站

  1. 主进程中调用Runtime.exec会创建一个子进程,用于执行shell脚本。子进程创建后会和主进程分别独立运行。

  2. 因为主进程需要等待脚本执行完成,然后对脚本返回值或输出进行处理,所以一般都是主进程调用Process.waitfor等待子进程完成。

  3. 但子进程执行过程就是不断的打印信息。注:主进程中可以通过Process.getInputStream和Process.getErrorStream获取并处理。

  4. 这时候子进程不断向主进程发送数据,而主进程调用Process.waitfor后已挂起。当子进程和主进程之间的缓冲区塞满后,子进程不能继续写数据,然后也会挂起。

  5. 这样子进程等待主进程读取数据,主进程等待子进程结束,两个进程相互等待,最终导致死锁。

解决方案:

开两个线程在waitfor()命令之前读出窗口的标准输出缓冲区和标准错误流的内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
new Thread() {
@Override
public void run() {
BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = null;

try {
while ((line = in.readLine()) != null) {
log.info("datax执行的结果为: "+line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}.start();

new Thread(){
@Override
public void run()
{
BufferedReader err = new BufferedReader(new InputStreamReader(process.getErrorStream()));
String line = null;
StringBuilder result=new StringBuilder();
try
{
while((line = err.readLine()) != null)
{
result.append(line);
}
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
try
{
err.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
}.start();