2013-10-15 2 views
1

Мне нужен блокирующий объект для запуска некоторых событий. A (один) Потребителю следует дождаться появления триггера. Затем он делает кое-что. Затем он снова ждет спусковой крючок. Триггеры активируются несколькими различными потоками (Производители). Но производители не производят никаких данных. Семантический смысл такого триггера: «Потребитель должен что-то сделать» (например, пересчитать некоторые значения, поскольку базовые данные изменились). Это означает, что даже если триггер активирован несколько раз, он должен появиться для Потребителя как один триггер.Какой блокирующий объект использовать?

Я думал об использовании 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?

+0

Я думаю, что вы ищете 'java.util.concurrent.locks.Condition' –

+0

синхронизируется просто для этого случая? – user987339

+1

Вы выполняете простые операции с синхронизацией и wait(), notify(). – UDPLover

ответ

2

Вы могли бы решить эту проблему с ArrayBlockingQueue емкостью одного:

public class Trigger{ 
    private final ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(1); 

    public void trigger(){ 
    queue.offer("foo"); 
    } 

    public void waitForTrigger(){ 
    queue.take(); 
    } 
} 
+0

Это, кажется, лучшее решение. Я не думал об использовании 'offer()'. Поскольку 'offer()' не блокирует производителя, он работает так, как я хочу. – radlan

+1

Вы можете легко избежать создания новых объектов, например. 'Queue ' + 'предложение (« foo »)' или использовать существующие объекты, такие как 'Boolean.TRUE' (это то, что [' Collections.newSetFromMap() '] (http://docs.oracle.com/javase/7/ docs/api/java/util/Collections.html # newSetFromMap% 28java.util.Map% 29) делает) – zapl

+0

@zapl Хорошая идея, я украл предложение вашей строки. –

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(); 
     } 
    } 
} 

Потребитель будет вызывать waitForTrigger() и заблокируют до производителя не называется триггером(). Если потребитель не заблокирован, то вызывающий триггер производителя() не повлияет ни на что.

+0

Конечно, вы правы. Я не думал о простом wait()/notify(). Спасибо, что помогает. Кажется, что даже ArrayBlockingQueue будет работать при использовании функции [offer()] (http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/BlockingQueue.html # offer (E)) метод, так как он не блокируется. – radlan

+0

@radlan, это вам нужно()? – UDPLover

+0

Argh! Кажется, я был не прав насчет wait()/notify(). Что делать, если продюсер вызывает trigger(), но ни один из пользователей не вызвал waitForTrigger()? – radlan

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() 
    } 
} 

An unlimitted количества производителей могут добавить «разрешения» на семафор и ваш потребитель просто берет их всех или ждет, по крайней мере, один появится ,

+0

Хотя ваш ответ кажется правильным, я принял его от Дункана Джонса, так как он имеет более легкий код. Но спасибо вам тоже. Это может сработать. – radlan

+0

@radlan 'wait' /' notify' имеет некоторые проблемы. Например, когда ваш потребитель в настоящее время не находится в 'waitForTrigger', каждое« уведомление », которое происходит в это время, просто переходит на poof, потому что их ничего не ждет. Это может быть желаемое свойство, но обычно это проблема. – zapl

+0

@radlan oops, забудьте, что я сказал, хорошее решение. – zapl

Смежные вопросы