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的代码,因为它的代码更简单。但也要感谢你。它也可以工作。@radlanwait
/notify
有一些问题。例如,当您的消费者当前不在waitForTrigger
中时,在此期间发生的每一次notify
都会失效,因为没有任何东西在等待他们。这可能是一个需要的属性,但通常是一个问题。@radlan oops,忘了我说的,这是一个很好的解决方案。如果有几个生产者在openTasks.acquire()
执行之前调用AddTasks()
,那么takeAllTasks()
调用之后执行(但在drainPermits()
调用之后),那么takeAllTasks()
将在下一次调用时立即返回。“我不确定那是否是你想要的行为。”邓肯·琼斯哦,对了,那不好。在末尾添加另一个drainPermits
应该可以解决这个问题。