Java IO输入流在读取外部C程序的标准输出和标准错误输出时会阻塞

4
我之前发布了同样的问题(Java reading standard output from an external program using inputstream),并在处理读取期间出现阻塞时找到了一些很好的建议(while(is.read()) != -1)),但我仍然无法解决问题。
在阅读了这个类似问题的答案后(Java InputStream blocking read,特别是Guss发布的答案),我开始相信如果程序是交互式的(即它从用户接收多个输入,并在随后的输入中呈现附加输出,并且只有在给出显式退出命令时才退出程序),那么使用is.read() != -1条件循环输入流不起作用。我承认我对多线程不太了解,但我认为我需要一种机制来及时暂停输入流线程(一个用于stdout,另一个用于stderr),当需要用户输入时,并在提供输入后恢复以防止阻塞。以下是我的当前代码,在标记的行上遇到了阻塞:
EGMProcess egm = new EGMProcess(new String[]{directory + "/egm", "-o",
                "CasinoA", "-v", "VendorA", "-s", "localhost:8080/gls/MessageRobot.action ",
                "-E", "glss_env_cert.pem", "-S", "glss_sig_cert.pem", "-C", "glsc_sig_cert.pem",
                "-d", "config", "-L", "config/log.txt", "-H", "GLSA-SampleHost"}, new String[]{"PATH=${PATH}"}, directory);
    egm.execute();

    BufferedReader stdout = new BufferedReader(new InputStreamReader(egm.getInputStream()));
    BufferedReader stderr = new BufferedReader(new InputStreamReader(egm.getErrorStream()));

    EGMStreamGobbler stdoutprocessor = new EGMStreamGobbler(stdout, egm);
    EGMStreamGobbler stderrprocessor = new EGMStreamGobbler(stderr, egm);

    BufferedWriter stdin = new BufferedWriter(new OutputStreamWriter(egm.getOutputStream()));


    stderrprocessor.run(); //<-- the block occurs here!
    stdoutprocessor.run();


    //EGM/Agent test cases


        //check bootstrap menu
        if(!checkSimpleResult("******** EGM Bootstrap Menu **********", egm))
        {
            String stdoutdump = egm.getStdOut();
            egm.cleanup();
            throw new Exception("can't find '******** EGM Bootstrap Menu **********'" +
                "in the stdout" + "\nStandard Output Dump:\n" + stdoutdump);
        }

        //select bootstrap
        stdin.write("1".toCharArray());
        stdin.flush();

        if(!checkSimpleResult("Enter port to receive msgs pushed from server ('0' for no push support)", egm)){
            String stdoutdump = egm.getStdOut();
            egm.cleanup();
            throw new Exception("can't find 'Enter port to receive msgs pushed from server ('0' for no push support)'" +
                    "in the stdout" + "\nStandard Output Dump:\n" + stdoutdump);
        }

public class EGMStreamGobbler implements Runnable{

}

很抱歉代码有点长,我的问题是:

1)是否有其他方法控制输入流(stdout, stderr)的处理过程,而不使用read()函数?或者我实现得不好?

2)多线程是开发输入流和输出流处理过程的正确策略吗?

注:如果有人能提供类似问题的解决方案,这将对我非常有帮助!

4个回答

8
替代

标签

stderrprocessor.run(); //<-- the block occurs here!
stdoutprocessor.run();

您需要启动线程:

Thread errThread = new Thread(stderrprocessor);
errThread.setDaemon( true );
errThread.start();

Thread outThread = new Thread(stdoutprocessor);
outThread.setDaemon( true );
outThread.start();

run()Runnable 接口中定义的一个方法。在新的 Thread 上调用 Thread.start() 方法会执行该方法。


2
  1. 如果你只是在一个Runnable上调用#run(),它不会并行执行。要并行运行它,你必须创建一个java.lang.Thread,执行你的Runnable的#run()。
  2. 流是否阻塞取决于流的两端。如果发送方没有发送任何数据或接收方没有接收到数据,则会出现阻塞情况。如果处理器在流被阻塞时必须执行某些操作,则需要在处理器内部生成一个(另一个)线程等待新数据,并在有新数据流入时中断备选进程。

1
首先,您需要了解Thread和Runnable。不直接调用Runnable.run(),而是设置线程来执行它并启动线程。
但更重要的是,三个独立的线程存在意味着需要进行一些仔细的设计。为什么要3个线程?你刚刚启动的两个线程和主线程。
我假设您应用程序的一般想法是等待某些输出到达,然后解释它并作为结果向您控制的应用程序发送命令?
因此,您的主线程需要等待其中一个读取器线程说“嗯!这很有趣,最好问问用户想要做什么。”
换句话说,您需要在读取器和写入器之间建立一些通信机制。这可以使用Java的事件机制实现。恐怕还需要更多的阅读。

1

这不是 nio 的创建原因吗?

我对 nio 中的通道不是很了解,但this answer可能会有所帮助。它展示了如何使用 nio 读取文件。可能会有用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接