radlan
radlan

Reputation: 2563

What blocking object to use?

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

Answers (3)

zapl
zapl

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

Duncan Jones
Duncan Jones

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

lol
lol

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

Related Questions