我有一个对象阻塞队列。

我想编写一个线程,该线程会阻塞直到队列中有一个对象。与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;
        }
    }
}
  1. 呼唤 peek() 检查值是否为 null 的 CPU 效率不高。

当以下程序的队列为空时,我发现系统上的 CPU 使用率达到 10%。

while (true) {
   Object o = queue.peek();
   if(o == null) continue;
   // omitted for the sake of brevity
}
  1. 添加 sleep() 增加了缓慢性。

  2. 使用将其添加回队列 putLast 会扰乱秩序。而且,这是一个需要锁的阻塞操作。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top