我几天前在这里发布了同样的问题(Java reading standard output from an external program using inputstream),我发现了一些在阅读时处理阻塞的极好的建议(while(is.read()) != -1)) , 但我仍然无法解决问题。
看完这个类似问题的答案后,
Java InputStream blocking read (特别是 Guss 发布的答案),
我开始相信,如果程序是交互式的,那么使用 is.read() != -1 条件循环输入流是行不通的(也就是说,它需要来自用户的多个输入,并在后续输入时呈现额外的输出,并且只有在给出明确的退出命令时程序才会退出)。我承认我对多线程知之甚少,但我认为我需要的是一种机制,可以在需要用户输入时立即暂停输入流线程(stdout、stderr 各一个),并在输入完成后恢复提供以防止阻塞。以下是我当前的代码,它在指示的行上遇到了一个 block :
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); }
...
<p> public class EGMStreamGobbler implements Runnable{</p> private BufferedReader instream; private EGMProcess egm; public EGMStreamGobbler(BufferedReader isr, EGMProcess aEGM) { instream = isr; egm = aEGM; } public void run() { try{ int c; while((c = instream.read()) != 1) { egm.processStdOutStream((char)c); } } catch(IOException e) { e.printStackTrace(); } }
}
对于代码的长度,我深表歉意,但我的问题是,
1) 有什么方法可以在不使用 read() 的情况下控制接收输入流(stdout、stderr)的过程?还是我只是执行得很糟糕?
2) 多线程是否是开发接收输入流和写入输出过程的正确策略?
PS:如果有人能提供类似问题的解决方案,那将对我有很大帮助!
最佳答案
代替
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.start()
在新的 Thread
中调用 Runnable
上的 run()
。
关于Java IO 输入流在读取外部 C 程序的标准输出和标准错误时阻塞,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1105569/