我有一个对象的阻塞队列。
我想写一个阻塞的线程,直到队列中有一个对象。与BlockingQueue.take()提供的功能类似。
但是,由于我不知道我是否能够成功处理该对象,我想只是peek()而不是删除该对象。我只想在能够成功处理它的情况下删除该对象。
所以,我想要一个阻塞的peek()函数。目前,如果队列为空,则peek()只返回javadocs。
我错过了什么吗?还有其他方法可以实现此功能吗?
修改
如果我只是使用线程安全队列并且偷看和睡觉了?
public void run() {
while (!exit) {
while (queue.size() != 0) {
Object o = queue.peek();
if (o != null) {
if (consume(o) == true) {
queue.remove();
} else {
Thread.sleep(10000); //need to backoff (60s) and try again
}
}
}
Thread.sleep(1000); //wait 1s for object on queue
}
}
请注意,我只有一个消费者线程和一个(单独的)生产者线程。我想这不如使用BlockingQueue有效......任何评论都赞赏。
答案 0 :(得分:14)
您可以使用LinkedBlockingDeque并从队列中物理删除该项目(使用takeLast()
),但在队列末尾时再次替换它,如果使用{处理失败{1}}。与此同时,您的“制作人”会使用putLast(E e)
向队列的前面添加元素。
您始终可以在自己的putFirst(E e)
实现中封装此行为,并提供Queue
方法,该方法在底层{{1}的幕后执行blockingPeek()
后跟takeLast()
}}。因此,从调用客户端的角度来看,元素永远不会从队列中删除。
答案 1 :(得分:6)
但是,由于我不知道我是否能够成功处理该对象,我想只是peek()而不是删除该对象。我只想在能够成功处理它的情况下删除该对象。
通常,它不是线程安全的。如果在peek()
之后确定对象可以成功处理,但在take()
删除和处理它之前,另一个线程会获取该对象,该怎么办?
答案 2 :(得分:2)
我唯一知道的是BlockingBuffer中的Apache Commons Collections:
如果调用get或remove 一个空的Buffer,即调用线程 等待添加或通知 addAll操作已经完成。
get()
相当于peek()
,Buffer
可以通过使用BlockingQueue
装饰UnboundedFifoBuffer来使其像BlockingBuffer
一样行事
答案 3 :(得分:1)
您是否还可以将事件侦听器队列添加到阻塞队列中,然后在(阻塞)队列中添加某些内容时,将事件发送给侦听器?你可以让你的线程阻塞,直到调用了actionPerformed方法。
答案 4 :(得分:1)
快速回答是,并非真的有一种方法可以阻止窥视,禁止用自己的阻塞peek()实现阻塞队列。
我错过了什么吗?
peek()在并发方面会很麻烦 -
听起来你可能会更好地删除项目并使用a处理它 Chain-of-responsibility pattern
编辑:re:你的最后一个例子:如果你只有一个消费者,你将永远不会删除队列中的对象 - 除非它在同一时间更新 - 在这种情况下你最好非常小心线程安全,可能不应该把项目放在队列中。
答案 5 :(得分:0)
看起来BlockingQueue本身没有您指定的功能。
我可能会尝试稍微重新解决这个问题:对于无法“正确处理”的对象,你会做什么?如果你只是将它们留在队列中,你必须在某个时候将它们拉出来处理它们。我建议要么弄清楚如何处理它们(通常,如果一个queue.get()给出任何类型的无效或坏的值,你可能只是把它放在地板上)或选择不同的数据结构。一个先进先出。
答案 6 :(得分:0)
答案 7 :(得分:0)
在成功处理上一个元素之前,请勿处理 next 元素。
public void run() {
Object lastSuccessfullyProcessedElement = null;
while (!exit) {
Object obj = lastSuccessfullyProcessedElement == null ? queue.take() : lastSuccessfullyProcessedElement; // blocking
boolean successful = process(obj);
if(!successful) {
lastSuccessfullyProcessedElement = obj;
} else {
lastSuccessfullyProcessedElement = null;
}
}
}
peek()
并检查该值是否为null不能有效利用CPU。当以下程序的队列为空时,我发现系统上的CPU使用率达到10%。
while (true) {
Object o = queue.peek();
if(o == null) continue;
// omitted for the sake of brevity
}
添加sleep()
会增加速度。
使用putLast
将其添加回队列将干扰顺序。而且,这是一个需要锁的阻塞操作。