Reputation: 2563
I need a blocking object for triggering some events. A (single) Consumer should wait for a trigger to occur. Then it does some stuff. Then it again waits for a trigger. The triggers are activated by multiple different threads (Producers). But the Producers do not produce any data. The semantic meaning of such a trigger is: "The Consumer has to do something" (for example recalculate some values, because the underlying data changed). That means even if the trigger is activated multiple times, it should appear to the Consumer as a single trigger.
I thought about using a CountDownLatch or an ArrayBlockingQueue, but they don't seem appropriate.
This is the trigger construct I'd like to use:
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.
}
}
Any ideas on what to use for the MagicBlockingObject
?
A BlockingQueue
seems appropriate, but I did not find a way to restrict it to a single content object without blocking the Producers, if the Queue is already filled.
Upvotes: 1
Views: 709
Reputation: 63955
java.util.concurrent
has a lot of nice utilities. wait
and notify
should be considered obsolete.
If I understand your problem you could try using a 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()
}
}
An unlimitted amount of producers can add "permits" to the semaphore and your consumer just takes them all or waits for at least one to appear.
Upvotes: 0
Reputation: 69399
You could solve this with an ArrayBlockingQueue
with a capacity of one:
public class Trigger{
private final ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(1);
public void trigger(){
queue.offer("foo");
}
public void waitForTrigger(){
queue.take();
}
}
Upvotes: 2
Reputation: 3390
What is problem with simple solution like this:
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 will call waitForTrigger() and will block till producer have not called trigger(). If consumer is not blocked then producer calling trigger() will not affect anything.
Upvotes: 1