java BlockingQueue 没有阻塞窥视?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1759803/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
java BlockingQueue does not have a blocking peek?
提问by rouble
I have a blocking queue of objects.
我有一个阻塞的对象队列。
I want to write a thread that blocks till there is a object on the queue. Similar to the functionality provided by BlockingQueue.take().
我想写一个线程,直到队列中有一个对象为止。类似于 BlockingQueue.take() 提供的功能。
However, since I do not know if I will be able to process the object successfully, I want to just peek() and not remove the object. I want to remove the object only if I am able to process it successfully.
但是,由于我不知道我是否能够成功处理该对象,所以我只想 peek() 而不是删除该对象。仅当我能够成功处理该对象时,我才想删除该对象。
So, I would like a blocking peek() function. Currently, peek() just returns if the queue is empty as per the javadocs.
所以,我想要一个阻塞的 peek() 函数。当前,如果根据 javadocs 队列为空,peek() 只会返回。
Am I missing something? Is there another way to achieve this functionality?
我错过了什么吗?有没有另一种方法来实现这个功能?
EDIT:
编辑:
Any thoughts on if I just used a thread safe queue and peeked and slept instead?
关于我是否只是使用线程安全队列并偷看和睡觉的任何想法?
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
}
}
Note that I only have one consumer thread and one (separate) producer thread. I guess this isn't as efficient as using a BlockingQueue... Any comments appreciated.
请注意,我只有一个消费者线程和一个(单独的)生产者线程。我想这不像使用 BlockingQueue 那样有效......感谢任何评论。
采纳答案by Adamski
You could use a LinkedBlockingDequeand physically remove the item from the queue (using takeLast()) but replace it again at the end of the queueif processing fails using putLast(E e). Meanwhile your "producers" would add elements to the frontof the queue using putFirst(E e).
您可以使用LinkedBlockingDeque并从队列中物理删除项目(使用takeLast()),但如果使用 处理失败,则在队列末尾再次替换它putLast(E e)。同时,您的“生产者”将使用 将元素添加到队列的前面putFirst(E e)。
You could always encapsulate this behaviour within your own Queueimplementation and provide a blockingPeek()method that performs takeLast()followed by putLast()behind the scenes on the underlying LinkedBlockingDeque. Hence from the calling client's perspective the element is never removed from your queue.
你总是可以封装这种行为你自己内Queue执行,并提供一个blockingPeek()方法,执行takeLast()之后putLast()对标的幕后LinkedBlockingDeque。因此,从调用客户端的角度来看,元素永远不会从您的队列中删除。
回答by Pavel Minaev
However, since I do not know if I will be able to process the object successfully, I want to just peek() and not remove the object. I want to remove the object only if I am able to process it successfully.
但是,由于我不知道我是否能够成功处理该对象,所以我只想 peek() 而不是删除该对象。仅当我能够成功处理该对象时,我才想删除该对象。
In general, it is not thread-safe. What if, after you peek()and determine that the object can be processed successfully, but before you take()it to remove and process, another thread takes that object?
一般来说,它不是线程安全的。如果在您peek()确定该对象可以成功处理之后,但在您take()删除和处理它之前,另一个线程获取了该对象,该怎么办?
回答by Zak
Could you also just add an event listener queue to your blocking queue, then when something is added to the (blocking)queue, send an event off to your listeners? You could have your thread block until it's actionPerformed method was called.
您是否也可以将一个事件侦听器队列添加到您的阻塞队列,然后在将某些内容添加到(阻塞)队列时,将事件发送给您的侦听器?你可以让你的线程阻塞,直到它的 actionPerformed 方法被调用。
回答by skaffman
The only thing I'm aware of that does this is BlockingBufferin Apache Commons Collections:
我意识到这一点的唯一的事情做,这是BlockingBuffer中的Apache Commons Collections中:
If either get or remove is called on an empty Buffer, the calling thread waits for notification that an add or addAll operation has completed.
如果在空缓冲区上调用 get 或 remove ,则调用线程将等待 add 或 addAll 操作已完成的通知。
get()is equivalent to peek(), and a Buffercan be made to act like BlockingQueueby decorating a UnboundedFifoBufferwith a BlockingBuffer
get()等价于peek(),并且Buffer可以BlockingQueue通过用 a装饰UnboundedFifoBuffer来使 a 表现得像BlockingBuffer
回答by nos
The quick answer is, not there's not really a way have a blocking peek, bar implementing a blocking queue with a blocking peek() yourself.
快速回答是,并不是真的没有办法进行阻塞查看,而是自己使用阻塞查看()来实现阻塞队列。
Am I missing something?
我错过了什么吗?
peek() can be troublesome with concurrency -
peek() 在并发方面可能很麻烦 -
- If you can't process your peek()'d message - it'll be left in the queue, unless you have multiple consumers.
- Who is going to get that object out of the queue if you can't process it ?
- If you have multiple consumers, you get a race condition between you peek()'ing and another thread also processing items, resulting in duplicate processing or worse.
- 如果您无法处理 peek() 的消息 - 它会留在队列中,除非您有多个消费者。
- 如果您无法处理该对象,谁会将该对象从队列中取出?
- 如果您有多个消费者,您会在 peek() 和另一个也在处理项目的线程之间遇到竞争条件,从而导致重复处理或更糟。
Sounds like you might be better off actually removing the item and process it using a Chain-of-responsibility pattern
听起来您最好实际删除该项目并使用 责任链模式对其进行处理
Edit: re: your last example: If you have only 1 consumer, you will never get rid of the object on the queue - unless it's updated in the mean time - in which case you'd better be very very careful about thread safety and probably shouldn't have put the item in the queue anyway.
编辑:re:你的最后一个例子:如果你只有 1 个消费者,你永远不会摆脱队列中的对象 - 除非它同时更新 - 在这种情况下,你最好非常小心线程安全和无论如何,可能不应该将该项目放入队列中。
回答by Jesse Glick
Not an answer per se, but: JDK-6653412claims this is not a valid use case.
本身不是答案,但是:JDK-6653412声称这不是一个有效的用例。
回答by JavaTechnical
The 'simplest' solution
“最简单”的解决方案
Do not process the nextelement until the previouselement is processed succesfully.
在成功处理前一个元素之前不要处理下一个元素。
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;
}
}
}
- Calling
peek()and checking if the value is null is not CPU efficient.
- 调用
peek()并检查值是否为空不是 CPU 效率的。
I have seen CPU usage going to 10% on my system when the queue is empty for the following program.
当以下程序的队列为空时,我已经看到我的系统上的 CPU 使用率上升到 10%。
while (true) {
Object o = queue.peek();
if(o == null) continue;
// omitted for the sake of brevity
}
Adding
sleep()adds slowness.Adding it back to the queue using
putLastwill disturb the order. Moreover, it is a blocking operation which requires locks.
添加
sleep()会增加速度。使用将其添加回队列
putLast会扰乱顺序。此外,它是一个需要锁的阻塞操作。
回答by Seth
Looks like BlockingQueue itself doesn't have the functionality you're specifying.
看起来 BlockingQueue 本身没有您指定的功能。
I might try to re-frame the problem a little though: what would you do with objects you can't "process correctly"? If you're just leaving them in the queue, you'll have to pull them out at some point and deal with them. I'd reccommend either figuring out how to process them (commonly, if a queue.get() gives any sort of invalid or bad value, you're probably OK to just drop it on the floor) or choosing a different data structure than a FIFO.
不过,我可能会尝试重新定义问题:对于无法“正确处理”的对象,您会怎么做?如果您只是将它们留在队列中,则必须在某个时候将它们拉出并处理它们。我建议要么弄清楚如何处理它们(通常,如果 queue.get() 给出任何类型的无效或错误的值,您可能可以将它放在地板上)或选择不同的数据结构而不是先进先出。

