调用者阻塞直到 getFoo() 准备好一个值?

我有一个 Java Thread,它公开了其他线程想要访问的属性:

I have a Java Thread which exposes a property which other threads want to access:

class MyThread extends Thread {
   private Foo foo;
   ...
   Foo getFoo() {
     return foo;
   }
   ...
   public void run() { 
     ...
     foo = makeTheFoo();
     ...
   }
}

问题是从它运行到 foo 可用需要很短的时间.调用者可以在此之前调用 getFoo() 并获得 null.我宁愿他们在初始化发生后简单地阻塞、等待并获取值.(foo 之后永远不会改变.)它准备好需要几毫秒,所以我对这种方法很满意.

The problem is that it takes some short time from the time this runs until foo is available. Callers may call getFoo() before this and get a null. I'd rather they simply block, wait, and get the value once initialization has occurred. (foo is never changed afterwards.) It will be a matter of milliseconds until it's ready, so I'm comfortable with this approach.

现在,我可以使用 wait()notifyAll() 实现这一点,并且有 95% 的机会我会做对.但我想知道你们会怎么做;java.util.concurrent 中是否有一个原语可以做到这一点,我错过了?

Now, I can make this happen with wait() and notifyAll() and there's a 95% chance I'll do it right. But I'm wondering how you all would do it; is there a primitive in java.util.concurrent that would do this, that I've missed?

或者,您将如何构建它?是的,让 foo 易变.是的,在内部锁 Object 上同步并将检查放入 while 循环,直到它不是 null.我错过了什么吗?

Or, how would you structure it? Yes, make foo volatile. Yes, synchronize on an internal lock Object and put the check in a while loop until it's not null. Am I missing anything?

推荐答案

如果 foo 只初始化一次,则 CountDownLatch 非常适合.

If foo is initialized only one time, a CountDownLatch is a great fit.

class MyThread extends Thread {

  private final CountDownLatch latch = new CountDownLatch(1);

  ...

  Foo getFoo() throws InterruptedException
  {
    latch.await(); /* Or use overload with timeout parameter. */
    return foo;
  }

  @Override
  public void run() {
    foo = makeTheFoo()
    latch.countDown();
  }

}

闩锁提供与 volatile 关键字相同的可见性行为,这意味着读取线程将看到线程分配的 foo 的值,即使 foo 未声明为 volatile.

Latches provide the same visibility behavior as the volatile keyword, meaning that reading threads will see the value of foo assigned by the thread, even though foo isn't declared volatile.

相关文章