【问题标题】:Producer-consumer queue with the ability to move items to the front生产者 - 消费者队列,能够将项目移动到前面
【发布时间】:2012-12-19 00:19:45
【问题描述】:

我使用 Java 的 LinkedBlockingDeque 实现了生产者-消费者模式,但我遇到了一个问题,即我有时想将一个项目(已经在队列中的某处)移动到队列的前面,以便更快地处理它.我永远不知道哪些已经排队的项目适合移到前面。因此,我希望将 LinkedBlockingDeque 替换为可以重新排序项目的东西。我有一个生产者和 2-4 个消费者(自定义线程实现),我在 Android 平台上。我怎样才能做到这一点?一些阻塞的双连接链表?

【问题讨论】:

  • 你能不能只做remove(Object o),在remove后检索对象,然后addFirst(Object o)。您使用迭代器检查 Deque 中的对象。
  • 我是这样做的,效果很好。如果它足够靠近前面,我想要一个不移动项目的功能,所以我不会得到不必要的删除。有没有一种快速的方法(使用 LinkedBlockingDeque)来检查队列中的项目有多远?快速我的意思是 O(1),最大 O(log N) 并且不复制整个队列。
  • @Tom Cammann 如果您将该评论作为答案发布,我将接受它,因为这是我收到的最佳建议

标签: java android concurrency


【解决方案1】:

来自我的评论:

您可以使用remove(Object o) 检索对象并将其从队列中删除,然后使用addFirst(Object o) 将其添加到队列的前面。这将产生对该对象进行优先级排序的效果。

您使用迭代器检查 Deque 中的对象。但是要非常小心ConcurrentModificationException,因为如果您在一个线程中访问集合并在另一个线程中对其进行修改,则可能会引发它们,但是如果您使用的是阻塞队列,这应该不是问题。

来自BlockingQueueJavadoc:

BlockingQueue 实现是线程安全的。所有排队方法 使用内部锁或其他形式以原子方式实现其效果 并发控制。但是,批量收集操作 addAll、containsAll、retainAll 和 removeAll 不一定 除非在实现中另有说明,否则以原子方式执行。 因此,例如,addAll(c) 可能会失败(抛出 例外)在c中只添加了一些元素之后。

【讨论】:

    【解决方案2】:

    看看PriorityBlockingQueue。它可能会满足您的需求。您可以插入具有名义优先级的项目,然后当您想要调整某些元素的优先级时,将其从队列中删除并重新添加新的优先级。

    【讨论】:

    • 那有一个问题,我必须记住最大的优先级,这个优先级总是会增加。嗯,但这应该不是什么大问题,因为我不应该在每个应用程序启动时产生超过百万个项目。我会试试的,谢谢。
    • 注意它使用较低的优先级作为队列的头部。我在想你可以添加所有优先级为 100 的项目(此时它们按进入顺序排序),并且只在需要时进行调整。您始终可以通过 peek 获得队列前面的优先级。
    • 这是个问题,我的队列中最多可以有 ~400 个项目
    • 如果你使用ints作为你的优先级,你可以有负优先级(这将更接近队列的前面)。所以,你可以去 -2^31,或大约 -20 亿。此外,队列允许您使用Comparator 定义优先级,因此您可以在现实中使用任何您想要的东西。如果您喜欢更高的优先级数字,请定义您的 Comparator 来执行此操作。
    • 我意识到,当我必须删除对象、更改优先级然后将其放回时,我可以按照 Tom Cammann 在评论中所说的去做。我已经以这种方式实现了它,它给了我比我以前的实现更好的结果。
    猜你喜欢
    • 2012-01-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-22
    • 1970-01-01
    相关资源
    最近更新 更多