【问题标题】:Choosing a data structure for a variant of producer consumer problem为生产者消费者问题的变体选择数据结构
【发布时间】:2011-04-28 09:05:27
【问题描述】:

现在,我有一个队列,有多个生产者和单个消费者。

消费者线程操作很慢。另外,消费者通过 peek 操作从队列中取出元素,直到消费操作完成,才能将元素从队列中移除。这是因为生产者线程作为一个边操作也会对在那个时间点未完全处理的所有元素进行快照。

现在,我想更改我的代码以支持多个消费者。所以,假设我有三个线程,一个线程将获取第一个元素,可以通过 peek 操作读取。 第二个消费者线程可以获取第二个元素,但我无法检索它,因为队列不支持检索第二个元素。

所以,使用标准 ConcurrentLinkedQueue(我现在正在使用)的选项已经取消。

我正在考虑使用优先级队列,但是我必须为每个元素关联一个标志,告诉我该元素是否已被某个线程使用。

哪种数据结构最适合这个问题?

【问题讨论】:

    标签: java data-structures producer-consumer


    【解决方案1】:

    听起来你真的应该有两个队列:

    • 未处理
    • 进行中

    消费者会原子地(通过锁)从未处理的队列中拉出并添加到进行中的队列中。这样多个消费者可以同时工作......但生产者仍然可以在需要时拍摄两个队列的快照。当消费者完成一项任务时,它会将其从正在进行的队列中删除。 (这实际上不需要是一个队列,因为没有什么可以从中“拉”出。只是一些您可以轻松添加和删除的集合。)

    鉴于您需要锁定以使传输原子化,您可能不需要底层队列成为并发队列 - 您已经保护了所有共享访问。

    【讨论】:

      【解决方案2】:

      我同意 Jon Skeet (+1) 的观点,因为您需要两个存储来记录等待和进行中的项目。我会使用LinkedBlockingQueue 并让您的每个消费者在其上调用take()。当一个元素到达队列时,它将被其中一个消费者占用。

      记录正在进行的内容和完成的内容将是单独的操作。我将维护所有尚未完成的项目的HashSet,我的生产者将首先(原子地)将项目添加到未完成项目的 HashSet 中,然后将项目弹出队列。一旦消费者完成它的工作,它就会从 HashSet 中删除该项目。

      您的生产者可以扫描 HashSet 以确定未完成的内容。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-27
        • 2011-08-29
        相关资源
        最近更新 更多