Java 使用什么阻塞对象?

Java 使用什么阻塞对象?,java,multithreading,blocking,Java,Multithreading,Blocking,我需要一个阻塞对象来触发一些事件。 (单个)使用者应等待触发器发生。然后它会做一些事情。然后它再次等待触发器。 触发器由多个不同的线程(生产者)激活。但制作人不提供任何数据。这种触发器的语义含义是:“消费者必须做一些事情”(例如,重新计算一些值,因为基础数据发生了变化)。 这意味着,即使触发器被激活多次,消费者也应该将其视为单个触发器 我曾想过使用a或an,但它们似乎不合适 这是我想使用的触发器构造: public class Trigger{ private final MagicBloc

我需要一个阻塞对象来触发一些事件。 (单个)使用者应等待触发器发生。然后它会做一些事情。然后它再次等待触发器。 触发器由多个不同的线程(生产者)激活。但制作人不提供任何数据。这种触发器的语义含义是:“消费者必须做一些事情”(例如,重新计算一些值,因为基础数据发生了变化)。
这意味着,即使触发器被激活多次,消费者也应该将其视为单个触发器

我曾想过使用a或an,但它们似乎不合适

这是我想使用的触发器构造:

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
似乎合适,但如果队列已满,我没有找到一种方法将其限制为单个内容对象而不阻止生产者。

像这样的简单解决方案有什么问题:

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()并将阻止,直到生产者尚未调用触发器()。如果消费者没有被阻止,那么生产者调用trigger()将不会影响任何事情。

java.util.concurrent
有很多很好的实用程序<代码>等待和
通知
应视为过时

如果我了解您的问题,您可以尝试使用
信号灯

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

未授权数量的生产者可以向信号量添加“许可证”,而您的消费者只需获取所有许可证或等待至少一个许可证出现。

您可以使用容量为1的
阵列锁定队列解决此问题:

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

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

  public void waitForTrigger(){
    queue.take();
  }
}
公共类触发器{
私有最终ArrayBlockingQueue队列=新ArrayBlockingQueue(1);
公共无效触发器(){
排队。报价(“foo”);
} 
公共空间{
queue.take();
}
}

我认为您正在寻找
java.util.concurrent.locks.Condition
是否已同步到simple?对于这种情况,您可以使用synchonize()和wait(),notify()调用来执行simple。“如果触发器被多次激活,消费者会认为它是单个触发器”-这是非常危险的设计决策,由于某些激活被忽略。您必须仔细考虑消费者清除触发器的方式/时间,因为它会影响哪些激活被忽略。@AlexeiKaigorodov我不这么认为。你认为问题出在哪里?消费者不会手动清除触发器,而只会使用触发器。在通知消费者之前,1个或10个生产商是否激活了触发器并不重要。你认为邓肯·琼斯的解决方案有什么问题吗?当然,你是对的。我没有想到简单的wait()/notify()。谢谢,这很有帮助。使用该方法时,即使是ArrayBlockingQueue也可以工作,因为它不会阻塞。@radlan,这是您需要的吗()?Argh!看来我说的wait()/notify()不对。如果生产者调用trigger(),但消费者还没有调用waitForTrigger(),那么什么也不会发生。简单的生产者将完成方法。但若消费者调用了blockingLatch.wait(),则消费者将收到通知并解除阻塞。是的。这就是问题所在。:-)因此,邓肯·琼斯的建议更适合我的情况。这似乎是最好的解决方案。我没有考虑使用
offer()
。由于
offer()
不会阻止制作者,因此它可以像我所希望的那样工作。您可以轻松避免创建新对象,例如
Queue
+
offer(“foo”)
或使用现有对象,例如
Boolean.TRUE
(这就是原因)@zapl好主意,我偷了您的字符串建议。尽管您的答案似乎正确,我接受了Duncan Jones的代码,因为它的代码更简单。但也要感谢你。它也可以工作。@radlan
wait
/
notify
有一些问题。例如,当您的消费者当前不在
waitForTrigger
中时,在此期间发生的每一次
notify
都会失效,因为没有任何东西在等待他们。这可能是一个需要的属性,但通常是一个问题。@radlan oops,忘了我说的,这是一个很好的解决方案。如果有几个生产者在
openTasks.acquire()
执行之前调用
AddTasks()
,那么
takeAllTasks()
调用之后执行(但在
drainPermits()
调用之后),那么
takeAllTasks()
将在下一次调用时立即返回。“我不确定那是否是你想要的行为。”邓肯·琼斯哦,对了,那不好。在末尾添加另一个
drainPermits
应该可以解决这个问题。