当前位置: 动力学知识库 > 问答 > 编程问答 >

java - How To Delay Method Return Until File Is Completely Read

问题描述:

Consider the following code example, in which I removed all error handling code in order to keep it readable:

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;

}

}

So my class MyClass reads a log file in the background (in another thread) and updates an attribute myAttribute with every line it reads from the log file. As long as there are any entries in the log file and my attribute is updated, the return of the getter function getMyAttribute() should be delayed. As soon as there are no more entries in the log file, getMyAttribute() should return myAttribute.

Although this code example works as required, it does not seem to be the most elegant solution. It is not clear at all how long the thread should sleep in order to have an optimal result. If one simply removes the call to Thread.sleep in the getter function, the program freezes. But if I set the value of the sleep method too high, the execution also takes too long.

How can I achieve the same in a better way? I already had a look at Java multithreading / concurrent programming resources, but nothing (like Java's synchronized) seems to fit this situation.

网友答案:

Thanks to the comments, I had a look at synchronized / wait() / notify() again. So here is another working and more elegant solution:

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;
  }

}

But there may still be better solutions. Java luminary Josh Bloch strictly advises against using these methods in his book Effective Java 2nd Edition (from this answer):

Given the difficulty of using wait and notify correctly, you should use the higher-level concurrency utilities instead [...] using wait and notify directly is like programming in "concurrency assembly language", as compared to the higher-level language provided by java.util.concurrent. There is seldom, if ever, reason to use wait and notify in new code.

分享给朋友:
您可能感兴趣的文章:
随机阅读: