Runtime.exec never returns when reading system.in

2019-07-16 11:22发布

Here is my sample code, I want to handle the command from standard input while running a new sub process. However, the exec method never returns if I read the system.in. The command in the exec() is very simple and has nothing to do with the stdin.

I'm wondering about is there any way to solve this? How can I start a new sub process while start another thread reading stdin?

public static void main(String[] args){
    new Thread(new Runnable(){
        public void run(){
            BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
            String command = null;
            try{
                while((command = reader.readLine()) != null){
                    System.out.println("Command Received:" + command);
                }
            }catch(Exception ex){
                ex.printStackTrace();
                //failed to listening command
            }

        }
    }).start();
    Process process = null;
    try {
        process = Runtime.getRuntime().exec("java -cp C:/agenttest Test");
        System.out.println("never returns");
        process.waitFor();
    } catch (IOException e) {
        throw new RuntimeException( e );
    } catch (InterruptedException e) {
        throw new RuntimeException( e );
    }
}

The Test class is very simple, here is the Test.java

public static void main(String[] args){
    System.out.println("Standard out");
    System.out.println("Standard out");
    System.err.println("Standard err");
    System.out.println("Standard out");
    try{
        Thread.sleep(10000);
    }catch(InterruptedException ex){}
}

2条回答
Lonely孤独者°
2楼-- · 2019-07-16 11:43

The problem could be that you're not handling the error stream and input stream and are overrunning the platform's buffers. Try handling that output as per the famous article, When Runtime.exec() won't.

For example:

import java.io.*;

public class TestMain {
   private static final String JAVA_CMD = "java";
   private static final String CP = "-cp";

   // *** your CLASS_PATH and PROG Strings will of course be different ***
   private static final String CLASS_PATH = "C:/Users/hovercraft/Documents/workspace/Yr 2012A/bin";
   private static final String PROG = "yr12.m07.b.Test2";

   private static final String[] CMD_ARRAY = { JAVA_CMD, CP, CLASS_PATH, PROG };

   public static void main(String[] args) {
      new Thread(new Runnable() {
         public void run() {
            BufferedReader reader = new BufferedReader(new InputStreamReader(
                  System.in));
            String command = null;
            try {
               while ((command = reader.readLine()) != null) {
                  System.out.println("Command Received:" + command);
               }
            } catch (Exception ex) {
               ex.printStackTrace();
               // failed to listening command
            }

         }
      }).start();
      Process process = null;
      try {
         ProcessBuilder processBuilder = new ProcessBuilder(CMD_ARRAY);
         process = processBuilder.start();
         InputStream inputStream = process.getInputStream();
         setUpStreamGobbler(inputStream, System.out);

         InputStream errorStream = process.getErrorStream();
         setUpStreamGobbler(errorStream, System.err);

         System.out.println("never returns");
         process.waitFor();
      } catch (IOException e) {
         throw new RuntimeException(e);
      } catch (InterruptedException e) {
         throw new RuntimeException(e);
      }
   }

   public static void setUpStreamGobbler(final InputStream is, final PrintStream ps) {
      final InputStreamReader streamReader = new InputStreamReader(is);
      new Thread(new Runnable() {
         public void run() {
            BufferedReader br = new BufferedReader(streamReader);
            String line = null;
            try {
               while ((line = br.readLine()) != null) {
                  ps.println("process stream: " + line);
               }
            } catch (IOException e) {
               e.printStackTrace();
            } finally {
               try {
                  br.close();
               } catch (IOException e) {
                  e.printStackTrace();
               }
            }
         }
      }).start();
   }
}
查看更多
对你真心纯属浪费
3楼-- · 2019-07-16 11:59

You should keep reading the input stream, otherwise it will get blocked. It has nothing to do with JVM but the underyling operating system.

查看更多
登录 后发表回答