Process.waitFor () never returns

Process process = Runtime.getRuntime().exec("tasklist"); BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); process.waitFor(); 
+73
Mar 30 '11 at 8:26
source share
8 answers

There are many reasons why waitFor() does not return.

But usually it comes down to the fact that the executed command does not leave.

This, again, can have many reasons.

One common reason is that the process produces some output and you are not reading from the corresponding threads. This means that the process is blocked as soon as the buffer is full, and waits for your process to continue reading. Your process, in turn, is waiting for the completion of another process (which will not be because it is waiting for your process, ...). This is a classic deadlock situation.

You need to constantly read from the input process stream to ensure that it is not blocked.

There's a good article that explains all the pitfalls of Runtime.exec() and shows the paths around them called "When Runtime.exec () will not be" (yes, the article is from 2000, but the content is still applied!)

+119
Mar 30 '11 at 8:31
source share

It looks like you are not reading the result before you wait for it to complete. This is fine only if the output does not fill the buffer. If this happens, it will wait until you read the output, catch-22.

You may have some errors that you are not reading. This may cause the application to stop and wait. A simple way to do this is to redirect errors to regular output.

 ProcessBuilder pb = new ProcessBuilder("tasklist"); pb.redirectErrorStream(true); Process process = pb.start(); BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); String line; while ((line = reader.readLine()) != null) System.out.println("tasklist: " + line); process.waitFor(); 
+47
Mar 30 2018-11-11T00:
source share

Also from Java doc:

java.lang

Class process

Since some proprietary platforms provide a limited buffer size for standard input and output streams, the inability to write an input stream quickly or read the output stream of a subprocess can lead to blocking of the subprocess and even deadlock.

It is not possible to flush the input stream buffer (which channels go to the subprocess output stream) from the process can lead to blocking of the subprocess.

Try the following:

 Process process = Runtime.getRuntime().exec("tasklist"); BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); while ((reader.readLine()) != null) {} process.waitFor(); 
+32
Mar 30 '11 at 8:40
source share

I would like to add something to the previous answers, but since I have no comments for comments, I will just add an answer. This is aimed at Android users who program in Java.

In a post from RollingBoy, this code almost worked for me:

 Process process = Runtime.getRuntime().exec("tasklist"); BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); while ((reader.readLine()) != null) {} process.waitFor(); 

In my case, waitFor () was not released, because I was executing the instruction without returning ("ip adddr flush eth0"). An easy way to fix this is to simply ensure that you always return something in your statement. For me, this meant doing the following: "ip adddr flush eth0 & & amcho; echo done". You can read the buffer all day, but if nothing comes back, your stream will never fail.

Hope this helps someone!

+8
May 20 '15 at 20:20
source share

As already mentioned, you should consume stderr and stdout.

Compared to other answers, since Java 1.7 is even simpler. You no longer need to create themes for reading stderr and stdout.

Just use ProcessBuilder and use the redirectOutput methods in combination with redirectError or redirectErrorStream .

 String directory = "/working/dir"; File out = new File(...); // File to write stdout to File err = new File(...); // File to write stderr to ProcessBuilder builder = new ProcessBuilder(); builder.directory(new File(directory)); builder.command(command); builder.redirectOutput(out); // Redirect stdout to file if(out == err) { builder.redirectErrorStream(true); // Combine stderr into stdout } else { builder.redirectError(err); // Redirect stderr to file } Process process = builder.start(); 
+3
Oct 07 '17 at 3:25
source share

There are several possibilities:

  • You did not consume the entire result of the stdout process.
  • You did not consume the entire result of the stderr process.
  • The process expects input from you, and you did not provide it, or you did not close the stdin process.
  • The process rotates in a rigid loop.
+2
Apr 20 '16 at 10:21
source share

For the same reason, you can also use inheritIO() to map the Java console to the external console of the application, for example:

 ProcessBuilder pb = new ProcessBuilder(appPath, arguments); pb.directory(new File(appFile.getParent())); pb.inheritIO(); Process process = pb.start(); int success = process.waitFor(); 
+1
Apr 20 '16 at 9:37
source share

I think that I was observing a similar problem: some processes started, it seemed, they were successfully executed, but they never completed. The waitFor () function waited forever, except when I killed a process in the task manager.
However, everything worked well in cases where the command line length was 127 characters or shorter. If long file names are unavoidable, you might want to use environment variables that can allow you to keep the command line short. You can generate a batch file (using FileWriter) in which you set your environment variables before calling the program that you really want to run. The contents of such a batch may look like this:

  set INPUTFILE="C:\Directory 0\Subdirectory 1\AnyFileName" set OUTPUTFILE="C:\Directory 2\Subdirectory 3\AnotherFileName" set MYPROG="C:\Directory 4\Subdirectory 5\ExecutableFileName.exe" %MYPROG% %INPUTFILE% %OUTPUTFILE% 

The final step runs this batch file using Runtime.

0
Nov 28 2018-11-11T00:
source share



All Articles