Recently there is a need to start multiple child processes with a Java process to complete the concurrency task. Because the user must be given feedback on the task, the parent process is required to record the child process's life cycle.
The Exec method returns a process object that invokes the Waitfor method of the object within the current process, and then the parent process blocks the method, which is returned from WAITFOR only if the process ends.
I have written two classes to test:
One is the Father class:
public class Father {private static int count = 0;private static int total = 3;private static String target = "./hell.jar" ;p rivate static list<process> child = new arraylist<process> ();p ublic static void Main (string[] args) {Runti Me 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 Blocke.printstacktrace ();}} for (Process item:child) {try {item.waitfor ()} catch (Interruptedexception e) {//TODO auto-generated catch Blocke.prin Tstacktrace ();}} System.out.println ("All Work finished!");}}
Hell.jar is exported by sub-class son, with the following specific code:
public class Son {public static void main (string[] args) {for (int i = 0; i < 10000; i + +) {System.out.println (i);} System.exit (0);}}
But, but!
Obviously should end soon, the result full card 15 points more than.
Later on the internet to find out that it is a pit
The document reads:
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 cause the subprocess to block, and even deadlock.
The meaning is simply summed up: if the buffer is full, I'll hang up.
In other words, the child process fills the buffer that is written to stdout, so the child process hangs, and the parent process dies in a perpetual wait.
Knowing the reason, the solution is simple: consume the output.
My approach is to redirect.
But there seems to be a pit for exec redirection. Goolge a workaround with the following code:
public class Father {private static int count = 0;private static int total = 3;private static String target = "./hell.jar" ;p rivate static list<process> child = new arraylist<process> ();p ublic static void Main (string[] args) {Runti Me 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 "); Redirect the output of StdOut and stderr to 1.txt child.add (num);} catch (Exception e) {//TODO auto-generated catch Blocke.printstacktrace ();}} for (Process item:child) {try {item.waitfor ()} catch (Interruptedexception e) {//TODO auto-generated catch Blocke.prin Tstacktrace ();}} System.out.println ("All Work finished!");}}
And then it worked out.
Feelings:
BAT is ugly, there are so many holes in Java on Windows.
"Original" The parent process subprocess in Java--the Java runtime.getruntime (). exec