java BlockingQueue没有阻塞查看?
-
20-09-2019 - |
题
我有一个对象阻塞队列。
我想编写一个线程,该线程会阻塞直到队列中有一个对象。与BlockingQueue.take()提供的功能类似。
但是,由于我不知道是否能够成功处理该对象,因此我只想 peek() 而不是删除该对象。仅当我能够成功处理该对象时,我才想删除该对象。
所以,我想要一个阻塞 peek() 函数。目前,根据 javadoc,peek() 仅在队列为空时返回。
我错过了什么吗?还有其他方法可以实现此功能吗?
编辑:
如果我只是使用线程安全队列并偷看并睡觉,有什么想法吗?
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 有效......任何意见表示赞赏。
解决方案
您可以使用 LinkedBlockingDeque 上和物理上从队列中移出(使用takeLast()
)的项目,但在<强>的队列强>的端部使用putLast(E e)
如果处理失败,再次更换。同时您的“生产者”将元素添加到队列中使用的putFirst(E e)
的前强>
您总是可以封装你自己Queue
内实施这种行为,并提供执行blockingPeek()
随后在底层takeLast()
幕后putLast()
一个LinkedBlockingDeque
方法。因此,从调用客户端的角度来看,元件不会从您的队列中删除。
其他提示
不过,因为我不知道如果我将能够成功处理的对象,我想只是偷看(),而不是删除对象。我想删除的对象只如果我能成功地处理它。
在一般情况下,它不是线程安全的。如果,以后你peek()
,并确定该对象可以被成功地处理,但你take()
它捞出过程之前,另一个线程需要该对象?
我唯一知道的是 阻塞缓冲区 在 Apache 共享集合:
如果在空的缓冲区上调用get或删除,则调用线程等待通知添加或addall操作已完成。
get()
相当于 peek()
, ,和一个 Buffer
可以表现得像 BlockingQueue
通过装饰一个 无界Fifo缓冲区 与一个 BlockingBuffer
难道你也只需要添加一个事件监听器队列的阻塞队列,那么当事情被添加到(阻塞)队列,发送事件给您的听众?你可以有你的线程块,直到它的actionPerformed方法被调用。
简单的回答是,实际上没有办法进行阻塞查看,除非您自己使用阻塞查看()来实现阻塞队列。
我错过了什么吗?
peek() 对于并发来说可能会很麻烦 -
- 如果您无法处理您的 peek() 消息 - 它将被留在队列中,除非您有多个消费者。
- 如果您无法处理该对象,谁将把该对象从队列中取出?
- 如果您有多个消费者,您会在 peek() 和另一个也在处理项目的线程之间出现竞争条件,从而导致重复处理或更糟。
听起来你最好实际删除该项目并使用责任链模式
编辑:关于:你的最后一个例子:如果你只有 1 个消费者,你将永远不会删除队列中的对象 - 除非它同时更新 - 在这种情况下,你最好非常小心线程安全,并且可能不应该放置该项目无论如何在队列中。
看起来BlockingQueue的本身不具有你指定的功能。
我可能会尝试,但是有点重制帧的问题:你会使用对象,你不能“过程正确”吗?如果你只是让他们在排队,你必须将它们拉出来在某个时刻,并处理它们。我reccommend无论是搞清楚如何处理它们(通常,如果一个queue.get()提供任何形式的无效或不当值,你可能确定,只是砸在地板上),或者选择不同的数据结构比一个FIFO。
不是答案本身,而是: JDK-6653412 声称此不是有效的用例。
“最简单”的解决方案
不处理 下一个 元素直到 以前的 元素已成功处理。
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
会扰乱秩序。而且,这是一个需要锁的阻塞操作。