阻止FIFO队列能否跳过元素?

时间:2018-05-31 15:26:40

标签: java queue

简短版本:如何在Java中最好地实现阻塞FIFO队列,如果他们当时不符合某些标准,则能够暂时跳过或跳过队列中的项目它们是从队列中弹出的吗?

长版:

我在应用程序中使用ArrayBlockingQueue多年,并且它已经很好地用于我的目的。到目前为止,我只需要调用put()和take()。它工作得很好。

现在要求元素在通过take()检索时满足某些条件。如果它不符合标准,它应该返回队列,但与之前的位置相同。

想象一下国际机场海关的一条线路。出于某种原因,乘客只有在上线时才能获得海关申报表。在轮到他们之前,乘客们都在疯狂地涂鸦以完成他们的表格。线路前面有一名保安。当海关官员为下一位乘客做好准备时,保安会检查该线路上的第一位乘客是否填写了海关申报单。如果是这样,他将pasenger发送给海关官员。如果没有,他会检查第二名乘客,然后检查第三名乘客,直到他找到完成的人。他把那个人送给海关官员。每次海关官员自由时都会发生同样的情况,总是在线上开始第一位乘客。

在研究中我唯一想到的就是使用双端队列(deque)并从前面取出元素,直到找到符合条件的元素。然后按照我取下它们的相反顺序将元素放回到前面。

有人有推荐吗?

2 个答案:

答案 0 :(得分:2)

2个可能的建议取决于您是否能够监听项目的状态更改:

  • 如果这些项目在准备好后可以通知您,那么只需在它们到达时对它们进行编号,并在它们准备好后立即将它们移动到PriorityQueue。然后从PriorityQueue中拉出第一个项目,如果它是空的则阻止。

  • 如果您必须检查每个项目以确定其状态是否已更改,那么您别无选择,只能依次访问每个项目,从最旧的项目开始,直到您找到一个项目准备好了。在这种情况下,您实际上不需要Queue作为基础数据结构; LinkedList实际上更适合。

第二种情况不只是速度慢,而且处理完整的未准备好的物品队列也更糟糕;要么在重新启动之前在列表末尾暂停一段时间(同时阻止),要么阻塞行为等同于忙碌等待,因为它反复循环遍历项目。

(如果我坚持实施第二次,我会倾向于尝试动态调整等待重启时间,基于等待准备的累计时间总量和至少一个的预期概率我下次开始走列表时就完成了。)

答案 1 :(得分:0)

让您的结构创建第二个队列。弹出时,在整个结构上获取写锁定。暂时忽略主队列并首先检查辅助队列。如果它为空,请转到主队列。从主队列中弹出一个元素。如果准备就绪,请拿走并解除锁定。如果不是,请将其放入辅助队列,然后抓住另一个队列。重复,直到你准备好。

如果第一次尝试抓取辅助队列时辅助队列不为空,请循环访问辅助队列以查看其中是否有任何已准备好。

这样做的优点是你总能得到一个现在已经准备好的人。当然除非你耗尽你的主要队列,但是没有人准备好了,你可以做的不多。

这样做的缺点是,如果你有一些超级慢的人,那么辅助队列可能是个问题。您可以通过估计剩余时间或其他内容来解决此问题。此外,坏演员总是可能撒谎或以其他方式束缚你。但是,如果你没有办法抢占坏人,你无论如何都会遇到多线程问题。

这是一个非线程安全的算法版本 - 它只是在我的头顶,所以带上一粒盐。

class SnappyQueue<E> {
    Queue<E> main = ... // people waiting in line
    Queue<E> slugs = ... // people at the front but still writing
    void push(E e) { main.addLast(e); }
    E pop() {
        E first = slugs.peek();
        if(first != null) {
            for(E cur = slugs.pop(); cur != first; cur = slugs.pop()) {
                if(cur.isReady()) return cur; // we're done, one of the slugs is ready
                slugs.push(cur); // this slug isn't ready, put it back
            }
        }
        while(true) {
            E cur = main.pop();
            if(cur == null) return null; // nothing left
            if(cur.isReady()) return cur; // we found someone ready
            slugs.push(cur); // not ready, push them into the slug line
        }
    }
}