我正在用 Java 构建一个缓冲区,它将收集许多线程请求的写操作,并将它们作为一个组刷新,比如说每秒一次。我想给它一个名为 waitForFlush
的方法,该方法将阻塞调用它的线程,直到下一个刷新事件完成。同时,一个单独的独立线程正在循环中刷新和 hibernate 。所以我基本上是在寻找一种并发结构或模式,允许许多线程在特定点阻塞,然后同时释放它们,我发现 Java 的内置并发原语都不是真正匹配的.到目前为止我想出的最好的是 wait/notifyAll,如下所示:
public class Buffer {
private volatile long lastFlushTime = System.currentTimeMillis();
private final Object flushMonitor = new Object();
public void waitForFlush() {
long entryTime = System.currentTimeMillis();
synchronized(flushMonitor) {
while(lastFlushTime <= entryTime) {
flushMonitor.wait();
}
}
}
public void flush() {
// do flush stuff here
synchronized(flushMonitor) {
lastFlushTime = System.currentTimeMillis();
flushMonitor.notifyAll();
}
}
}
虽然我认为这在实践中会很好地工作,但 waitForNotify()
中的同步块(synchronized block)对我来说仍然有些不完美。理想情况下,对于此用例,您可以调用 wait()
而无需同步关联的对象,并且所有被阻塞的线程都将在 notifyAll( )
被调用,而不是一个一个地退出同步块(synchronized block)。
所以,一般来说,有没有比我上面概述的更好的方法来阻止和同时释放可变数量的线程(我认为 Semaphore 和 CountDownLatch 类只适用于固定数量的线程)?
最佳答案
尽管正如 Marko Topolnik 和 munyengm 提到的那样,CountDownLatch 只适用于一次性情况。它在循环场景中失败(即每个 CDL 只能 await
& countDown
一次)。然后您可能会考虑使用 CyclicBarrier,但在您的情况下会失败,因为您需要知道正在使用的线程数。
如果你可以使用 Java 7,我推荐 Phaser .您可以让单个线程向多个等待线程发送信号并重用。
final Phaser phaser = new Phaser(1);//register one thread to arrive
public void waitForFlush() {
int phase = phaser.getPhase();
phaser.awaitAdvance(phase);
}
public void flush() {
lastFlushTime = System.currentTimeMillis();
phaser.arrive(); //signals all waiting threads on the current phase and will increment the phase by 1
}
关于java - 在 Java 中阻塞并同时释放可变数量的线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11375683/