我有两个需要相互交谈的Java线程,我不确定我是否正确地进行此操作。
基本是这样的:我有线索,"跑步者"这将通过使用Apache exec库调用命令行来启动长时间运行的进程。另一个线程" monitor"将定期监视和报告系统状态。
部分内容涉及返回跑步过程从stdout获取的行。目前,运行器和监视器作为单独的线程运行。监视器具有对跑步者的引用,并且可以通过呼叫跑步者"获得标准输出来访问收集的输出(到目前为止)。方法
这似乎工作正常,但整个设置对我来说似乎并不是很好。部分地,我担心这个实现不是线程安全的,尽管我甚至不确定如何测试它。自从我完成多线程编程以来已经有一段时间了,所以我想知道是否有更好/更清洁的方式来做我想做的事情。代码看起来像这样:
public class Runner implements Callable<String>
{
private ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
private ByteArrayOutputStream errorStream = new ByteArrayOutputStream();
public String getStdOutLines()
{
return new String(outputStream.toByteArray());
}
public String getStdErrLines()
{
return new String(errorStream.toByteArray());
}
@Override
public String call() throws Exception
{
/*
Use apache exec to begin long-running process.
stdout and stderr are written to two local members (outputStream and errorStream).
This is done by the apache exec library.
*/
PumpStreamHandler streamHandler = new PumpStreamHandler(this.outputStream, this.errorStream);
DefaultExecuteResultHandler resultHandler = new DefaultExecuteResultHandler();
executor.setStreamHandler(streamHandler);
CommandLine cli = //Details not important here.
executor.execute(cli, resultHandler);
resultHandler.waitFor();
String resultsString = generateFinalResultString(outputStream, errorStream); //implementation details of this not important here.
return resultsString; /*some string calculated after the process has completed.*/
}
}
public class Monitor implements Runnable
{
private Runner runner;
public void setRunner(Runner r)
{
this.runner = r;
}
@Override
public void run()
{
try
{
while (!Thread.currentThread().interrupted())
{
//Call the functions on the other thread to get the stdout and stderr
commandStdOut = this.runner.getStdOutLines();
commandStdErr = this.runner.getStdErrLines();
doSendMonitoringMessage(commandStdOut, commandStdErr);
Thread.sleep(SOME_DELAY);
}
}
catch(InterruptedException e)
{
System.out.println("Monitor is shutting down");
}
}
}
public class ExecuteAllThis
{
public void doTheStuff()
{
System.out.println("begining...");
Runner runner = new Runner();
Monitor monitor = new Monitor();
monitor.setRunner(runner);
ExecutorService xservice = Executors.newFixedThreadpool(2);
xservice.execute(monitor);
Future<String> runnerFuture = xservice.submit(runner);
String result = runnerFuture.get(0);
System.out.println("result is: "+result);
}
编辑:我已经添加了一些关于我如何调用写入stdout和stderr字符串的长时间运行进程的详细信息,因为这比我最初更有意义实现。
答案 0 :(得分:0)
您的实施很好。
但是,理论上,变量outputStream
和errorStream
应该是volatile
,否则监控线程可能无法获得最新更新 - 理论上。
在一般情况下,将volatile
用于共享变量的另一个原因是防止读取损坏的状态。这个原因不适用于此,因为String
是不可变的。
如果您不确定,另一条建议是使用好的synchronized
。它可能比volatile
慢一点,但这通常不是问题;当然不是你的情况。