Java中的线上通信

时间:2015-05-11 18:55:52

标签: java multithreading

我有两个需要相互交谈的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字符串的长时间运行进程的详细信息,因为这比我最初更有意义实现。

1 个答案:

答案 0 :(得分:0)

您的实施很好。

但是,理论上,变量outputStreamerrorStream应该是volatile,否则监控线程可能无法获得最新更新 - 理论上。

在一般情况下,将volatile用于共享变量的另一个原因是防止读取损坏的状态。这个原因不适用于此,因为String是不可变的。

如果您不确定,另一条建议是使用好的synchronized。它可能比volatile慢一点,但这通常不是问题;当然不是你的情况。