我有一个 Java Thread
,它公开了其他线程想要访问的属性:
class MyThread extends Thread {
private Foo foo;
...
Foo getFoo() {
return foo;
}
...
public void run() {
...
foo = makeTheFoo();
...
}
}
问题是从运行到 foo
可用需要一些很短的时间。调用者可以在此之前调用 getFoo()
并获取 null
。我宁愿他们简单地阻塞、等待,并在初始化发生后获取值。 (foo
此后永远不会更改。)准备就绪只需几毫秒,因此我对这种方法感到满意。
现在,我可以使用 wait()
和 notifyAll()
实现这一点,并且有 95% 的机会我会做对。但我想知道你们会怎么做? java.util.concurrent 中是否有一个原语可以做到这一点,但我错过了?
或者,您将如何构建它?是的,让 foo
变得易失。是的,同步内部锁 Object
并将检查放入 while
循环中,直到它不为 null
。我错过了什么吗?
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();
...
}
}
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.
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?
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?
发布评论
评论(9)
如果
foo
仅初始化一次,则CountDownLatch
非常适合。锁存器提供与 volatile 关键字相同的可见性行为,这意味着读取线程将看到线程分配的 foo 值,即使 foo 也如此未声明
易失性
。If
foo
is initialized only one time, aCountDownLatch
is a great fit.Latches provide the same visibility behavior as the
volatile
keyword, meaning that reading threads will see the value offoo
assigned by the thread, even thoughfoo
isn't declaredvolatile
.一般来说,notify() 和notifyAll() 是您想要的方法。如果只有一个项目正在创建 Foo 并且许多线程可能会等待它,则 notification() 是危险的。但我认为这里还存在一些其他问题。
我不会让 Thread 成为存储 Foo 的地方。这样做意味着您必须在创建 Foo 之后保留一个线程。为什么不创建另一个对象来存储 Foo,并让创建线程写入它?
然后我将 getFoo() 测试 foo 并仅在它非空时等待(不要忘记将其与其自身以及与 foo setter 同步)。
In general notify() and notifyAll() are the methods you want. notify() is dangerous if only one item is creating the Foo and many threads might wait for it. But I think there are some other issues here.
I wouldn't make the Thread the place to store the Foo. Doing so means you have to keep a thread around after Foo is created. Why not make another object to store the Foo, and have the creating thread write to it?
Then I would have getFoo() test foo and only wait if it was non-null (don't forget to synchronize it with itself and with the foo setter).
我会使用任何 < code>BlockingQueue 位于
java.util.concurrent
中 更具体地说,如果有一个线程在等待 Foo 并且有一个线程在生成它,我会使用SynchronousQueue
如果有更多生产者和/或更多消费者,我的默认选项是LinkedBlockingQueue
,但其他实现可能更适合您的应用程序。然后你的代码就变成:I'd use any of the
BlockingQueue
's injava.util.concurrent
More specifically, if there is one thread waiting for Foo and one producing it I'd use aSynchronousQueue
in cases of more producers and/or more consumers my default option is aLinkedBlockingQueue
, but other implementations might be better suited to your application. Your code then becomes:尝试
CountDownLatch
:我不认为
wait
/notifyAll
会起作用,因为每个wait
都会期望一个 <代码>通知。您希望通知一次,然后不再需要通知,那么调用getFoo
的任何其他线程都会阻塞,直到foo
初始化,或者只获取foo
code> 如果已经初始化。Try the
CountDownLatch
:I don't think
wait
/notifyAll
will work, because everywait
will expect anotify
. You want to notify once and then never bother with notification again, then any other thread that's callinggetFoo
will either block untilfoo
is initialized or just getfoo
if it's already initialized.您可以使用 wait() 和 notification() 方法:
简单示例:
http://www.java-samples.com/showtutorial.php?tutorialid=306
You can use the the wait() and notify() methods:
Simple example here:
http://www.java-samples.com/showtutorial.php?tutorialid=306
据我了解,并发的东西是明确创建的,不是为了立即等待并做你想做的事 - 但如果可能的话。在你的情况下,你需要等待直到有可用的东西,所以你唯一的选择是,呃,
wait()
。总之,看来你描述的方式是唯一正确的方式。As I understand, concurrent stuff is created explicitly not to wait and do what you want right away — but if it is possible at all. In your case you need to wait until something is available, so your only option is, uh, to
wait()
. In short, it seems that the way you described it is the only correct way.如果初始化是一次性的,请尝试 java .util.concurrent.CountDownLatch。
If initialization is a one shot deal, try java.util.concurrent.CountDownLatch.
延迟初始化是一种选择吗?
Is lazy initialization an option?
也许尝试一下我奇特的 FutureValue 课程......
Maybe try my fancy FutureValue class...