【问题标题】:JAVA - Sending data to child process in a loopJAVA - 在循环中向子进程发送数据
【发布时间】:2015-02-05 12:05:07
【问题描述】:

我想向子进程和它们发送一些字符串,这会将我以大写形式发送回来。这个想法是我放一个空字符串,两个过程都会停止。 第一次效果很好,但下一次过程卡在第二次,我需要强制关闭。

父亲代码 ->

public class padre {
public static void main(String[] args){
    System.out.println("Soy el padre");
    try {
        Process p = Runtime.getRuntime().exec("java -jar C:\\Users\\Cristian\\Desktop\\hijo.jar");

        InputStreamReader isr = new InputStreamReader(System.in);
        BufferedReader escritorPadre = new BufferedReader(isr);

        //Leer del hijo
        BufferedReader brHijo = new BufferedReader(new InputStreamReader(p.getInputStream()));
        BufferedReader brHijoError = new BufferedReader(new InputStreamReader(p.getErrorStream()));
        //EScribir en el hijo
        OutputStream os = p.getOutputStream();


        String lineaConsola;
        while((lineaConsola = escritorPadre.readLine()).isEmpty() == false){

            lineaConsola +="\n";
            os.write(lineaConsola.getBytes());
            os.flush();


            String linea;
            while((linea = brHijo.readLine()) != null){
                System.out.println(linea);
                System.out.println("Atascado en el while del padre");
            }
            while((linea = brHijoError.readLine()) != null){
                System.out.println(linea);
                System.out.println("Atascado en el while del padre error");
            }

        }






    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

}

}

子代码->

public class hijo {
public static void main(String[] args){
    InputStreamReader in = new InputStreamReader(System.in);
    BufferedReader br = new BufferedReader(in);
    String linea;
    try {
        while(!(linea = br.readLine()).isEmpty()){
            System.out.println("Hijo -> " + linea.toUpperCase()+"\n");
            System.out.println("Atascado en el while del hijo");
        }
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

}

【问题讨论】:

  • 为什么会产生启动多个 JVM 而不是同时调用另一个方法的开销?
  • 而且你不需要空行。仅关闭输出流将在子进程的输入流处产生流结束。你不需要其他任何东西。

标签: java process inputstream outputstream


【解决方案1】:

这里有几个问题。

  • 首先,在您的主循环(父子循环)中,您没有检查文件结尾。这意味着您可以从流阅读器获得null,当您尝试访问isEmpty() 时,您将获得NullPointerException

  • 其次,您永远不会将空行传递给子进程,因为一旦您从escritorPadre.readLine() 获得的行为空,您就会退出while 循环。所以检查isEmpty() 的儿子是徒劳的。最好一退出就关闭给儿子的流(无论如何,当你完成它们时,你总是必须关闭它们),并在儿子方面处理null

  • 但最重要的是:您从儿子那里读取的循环总是会卡住,因为您只会在流结束时从儿子那里获得null。如果儿子在其输出流上使用close()(或儿子终止),您只会得到流结束。但是,如果您确实在子端使用了close(),您将无法再次写入标准输出。

    所以你的循环一直在等待儿子写别的东西,而儿子在写东西之前正在等待父亲写别的东西。所以进程处于死锁状态。

您可以决定儿子应该发送一些特殊的输出(一个空行),以便您知道何时停止读取其输出。

但是你有一个标准错误的问题。从儿子的输出中读取完后,您开始从标准错误中读取。因此,为了让您离开该循环,您还必须在每次写入输出后打印一个空行到标准错误,并且还要在每个catch 打印的堆栈跟踪中添加一个空行。然后,您还必须在父亲的循环中添加一个空行检查,以读取儿子的标准错误。

就个人而言,我认为这不是很优雅。但这是可行的。

无论如何,为了让您开始,在父亲方面,您应该确保关闭所有流并在读取时检查 null。比如:

try {
    p = Runtime.getRuntime().exec("java -jar C:\\Users\\Cristian\\Desktop\\hijo.jar");
} catch ( IOException e ) {
    e.printStackTrace();
    return;
}

// Use try-with-resources to open all the streams and readers
// so that they will be closed automatically
try (
    BufferedReader escritorPadre = new BufferedReader(new InputStreamReader(System.in));

    //Leer del hijo
    BufferedReader brHijo = new BufferedReader(new InputStreamReader(p.getInputStream()));
    BufferedReader brHijoError = new BufferedReader(new InputStreamReader(p.getErrorStream()));
    //EScribir en el hijo
    OutputStream os = p.getOutputStream();
) {

    String lineaConsola;

    // Read until either end-of-file or empty line
    while((lineaConsola = escritorPadre.readLine()) != null && ! lineaConsola.isEmpty()){

       ... // I ommitted the reading from the son until you decide how you want to arrange it.

    }

} catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

在儿子中,还要确保关闭所有资源或使用 try-with-resources,并检查 null 和空行:

try (
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
){
    while((linea = br.readLine()) != null && ! linea.isEmpty()){
        System.out.println("Hijo -> " + linea.toUpperCase()+"\n");
        System.out.println("Atascado en el while del hijo");
        // Decide how you want to handle telling the father that output is done
    }
} catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-05-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-23
    • 2011-09-01
    相关资源
    最近更新 更多