【原创】java中的父进程子进程 —— 坑爹的java Runtime.getRuntime().exec

时间:2022-05-15 23:34:08

最近有一个需求,需要用一个java进程启动多个子进程来完成并发任务。由于必须给用户完成任务的反馈,所以需要父进程记录子进程的生命周期。

exec方法返回一个Process对象,在当前进程内调用该对象的waitFor方法,然后父进程就会在该方法阻塞,那么只有在该Process结束的情况下,才会从waitFor中返回。

我写了两个类来测试:

一个是Father类:

public class Father {
private static int count = 0;
private static int total = 3;
private static String target = "./hell.jar";
private static List<Process> child = new ArrayList<Process> (); public static void main (String[] args) {
Runtime run = Runtime.getRuntime();
System.out.println("wait..");
for (int i = 0; i < total; i ++) {
try {
Process num = run.exec("java -jar " + target);
child.add(num);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
for (Process item : child) {
try {
item.waitFor();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("All work finished!");
}
}

  

hell.jar由子类son导出,具体代码如下:

public class Son {
public static void main (String[] args) {
for (int i = 0; i < 10000; i ++) {
System.out.println(i);
}
System.exit(0); }
}

  

可是,可是!

明明应该很快结束,结果整整卡了15分有余。。

后来上网查了,才发现这是个坑

文档中如此写道:

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.

这意思简单概括为:缓冲区如果满了,爷就挂起来

换言之,子进程把写往stdout的缓冲区占满了,所以子进程挂起了,于是父进程就要消逝在永久的等待中了。

了解了原因,解决办法就简单了:消耗掉输出。

我的办法是重定向。

但是对exec重定向似乎也有坑。。Goolge了一个解决办法,具体代码如下:

public class Father {
private static int count = 0;
private static int total = 3;
private static String target = "./hell.jar";
private static List<Process> child = new ArrayList<Process> (); public static void main (String[] args) {
Runtime run = Runtime.getRuntime();
System.out.println("wait..");
for (int i = 0; i < total; i ++) {
try {
Process num = run.exec("cmd /c java -jar " + target + " 1>>1.txt 2>&1"); // 把stdout和stderr的输出重定向到1.txt中
child.add(num);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
for (Process item : child) {
try {
item.waitFor();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("All work finished!");
}
}

  

然后就成功了。

感想:

bat真丑,windows上java的坑真多