我需要一个阻塞对象来触发某些事件。 (单个)消费者应该等待触发发生。然后它做了一些事情。然后它再次等待触发器。 触发器由多个不同的线程(生产者)激活。但生产者不会产生任何数据。这种触发器的语义含义是:“消费者必须做某事”(例如重新计算某些值,因为基础数据已更改)。 这意味着即使触发器被多次激活,它也应该被消费者视为单个触发器。
我考虑使用CountDownLatch或ArrayBlockingQueue,但它们似乎不合适。
这是我想要使用的触发器构造:
public class Trigger{
private final MagicBlockingObject blockingLatch;
public void trigger(){
//activate the blockingLatch, so that a call to waitForTrigger() returns
}
public void waitForTrigger(){
//read from the blockingLatch. This should block until trigger() is called.
}
}
关于MagicBlockingObject
使用什么的任何想法?
BlockingQueue
似乎合适,但如果队列已经填满,我没有找到将其限制为单个内容对象而不阻塞生产者的方法。
答案 0 :(得分:2)
您可以使用容量为1的ArrayBlockingQueue
解决此问题:
public class Trigger{
private final ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(1);
public void trigger(){
queue.offer("foo");
}
public void waitForTrigger(){
queue.take();
}
}
答案 1 :(得分:1)
这样的简单解决方案有什么问题:
public class Trigger {
private final Object blockingLatch = new Object();
public void trigger() {
//activate the blockingLatch, so that a call to waitForTrigger() returns
synchronized(blockingLatch){
blockingLatch.notify();
}
}
public void waitForTrigger() throws InterruptedException {
//read from the blockingLatch. This should block until trigger() is called.
synchronized(blockingLatch){
blockingLatch.wait();
}
}
}
Consumer将调用waitForTrigger()并阻塞直到生产者没有调用trigger()。如果消费者没有被阻止,那么生产者调用trigger()不会影响任何事情。
答案 2 :(得分:0)
java.util.concurrent
有很多不错的实用程序。 wait
和notify
应该被视为过时。
如果我了解您的问题,您可以尝试使用Semaphore
public class Blocking {
private final Semaphore openTasks = new Semaphore(0);
public void addTask() {
// add 1
openTasks.release();
}
public void takeAllTasks() throws InterruptedException {
int immediately = openTasks.drainPermits();
if (immediately > 0) {
// there was a task, no need to wait
return;
}
// wait for task
openTasks.acquire();
// ensure we leave this method without leaving permits
openTasks.drainPermits()
}
}
无限制的生产者可以向信号量添加“许可证”,而您的消费者只需将其全部或等待至少一个出现。