如何延迟方法返回直到完全读取文件

时间:2014-07-03 10:29:07

标签: java multithreading concurrency

考虑以下代码示例,其中我删除了所有错误处理代码以使其可读:

public class MyClass {

  protected Something myAttribute;
  protected boolean busy = true;

  public ReactiveLogger() {
    new Thread(new FileListener()).start();
  }

  private class FileListener implements Runnable {

    @Override
    public void run() {
      RandomAccessFile raf = new RandomAccessFile(LOG_FILE, "rw");
      while (true) {
        final String line = cutFirstLine(raf);
        if (line == null) {
          busy = false;
          Thread.sleep(1000);
        } else {
          busy = true;
          // handeLogMessage changes myAttribute
          handleLogMessage(line);
        }
      }
    }

    // definition of cutFirstLine etc.

  }

  // definition of handleLogMessage etc.

  public Something getSomething() {
    while (busy) {
      Thread.sleep(100);
    }
    return myAttribute;
  }

}

所以我的类MyClass在后​​台读取一个日志文件(在另一个线程中),并使用从日志文件中读取的每一行更新属性myAttribute。只要日志文件中有任何条目并且我的属性更新,就应该延迟getter函数getMyAttribute()的返回。只要日志文件中没有其他条目,getMyAttribute()就应该返回myAttribute

尽管此代码示例按要求运行,但它似乎不是最优雅的解决方案。根本不清楚线程应该睡多长时间才能获得最佳结果。如果只是在getter函数中删除对Thread.sleep的调用,程序会冻结。但是如果我将sleep方法的值设置得太高,执行也需要很长时间。

如何以更好的方式实现同​​样的目标?我已经看过Java多线程/并发编程资源,但没有任何东西(比如Java synchronized)似乎适合这种情况。

1 个答案:

答案 0 :(得分:1)

感谢您的评论,我再次查看了synchronized / wait() / notify()。所以这是另一种工作和更优雅的解决方案:

public class MyClass {

  protected Something myAttribute;
  protected boolean busy = true;
  protected final Object lock = new Object();

  public ReactiveLogger() {
    new Thread(new FileListener()).start();
  }

  private class FileListener implements Runnable {

    @Override
    public void run() {
      RandomAccessFile raf = new RandomAccessFile(LOG_FILE, "rw");
      while (true) {
        final String line = cutFirstLine(raf);
        if (line == null) {
          busy = false;
          synchronized (lock) {
            lock.notifyAll();
          }
          Thread.sleep(1000);
        } else {
          busy = true;
          // handeLogMessage changes myAttribute
          handleLogMessage(line);
        }
      }
    }

    // definition of cutFirstLine etc.

  }

  // definition of handleLogMessage etc.

  public Something getSomething() {
    synchronized (lock) {
      while (busy) {
        lock.wait();
      }
    }
    return myAttribute;
  }

}

但可能仍有更好的解决方案。 Java杰出人物Josh Bloch严格建议不要在他的书 Effective Java 2nd Edition (来自this answer)中使用这些方法:

  

鉴于正确使用waitnotify的困难,您应该使用更高级别的并发工具 [...]使用wait和与notify提供的高级语言相比,java.util.concurrent直接类似于“并发汇编语言”编程。 很少(如果有的话)有理由在新代码中使用waitnotify