JAVA-在循环中将数据发送到子进程

JAVA-在循环中将数据发送到子进程,java,process,inputstream,outputstream,Java,Process,Inputstream,Outputstream,我想把一些字符串发送给一个子进程,然后用大写字母返回。我的想法是,我把一个空字符串,这两个进程将停止。 第一次效果很好,但下一次过程在第二次被卡住时,我需要强制关闭 父亲代码-> public class padre { public static void main(String[] args){ System.out.println("Soy el padre"); try { Process p = Runtime.getRuntime().exec("ja

我想把一些字符串发送给一个子进程,然后用大写字母返回。我的想法是,我把一个空字符串,这两个进程将停止。 第一次效果很好,但下一次过程在第二次被卡住时,我需要强制关闭

父亲代码->

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();
    }
}

}这里有几个问题

首先,在父循环和子循环中,您并没有检查文件的结尾。这意味着您可以从流读取器获得null,并且当您尝试访问isEmpty时,将获得一个NullPointerException

其次,永远不要将空行传递给子进程,因为一旦从escritorPadre.readLine获得的行为空,就可以退出while循环。因此,儿子检查isEmpty是徒劳的。最好在退出时立即关闭子流,不管怎样,在完成流时始终必须关闭它们,并在子端处理null

但最重要的是:用于读取子循环的循环总是会被卡住,因为您只会从流末尾的子端得到null。并且,只有当子系统在其输出流上使用close或子系统终止时,您才能得到流的末尾。但是,如果在子端使用close,您将无法再次写入标准输出

因此,你的循环一直在等待儿子写其他东西,而儿子则在等待父亲写其他东西之后再写。因此,该过程处于死锁状态

你可以决定儿子应该发送一些特殊的输出,一个空行,这样你就知道什么时候停止读取它的输出

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

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

无论如何,为了让您开始,在父端,您应该确保关闭所有流,并在读取时检查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();
}
在son中,还要确保关闭所有资源或使用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();
}

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