可交换的工作队列

时间:2009-03-11 19:34:09

标签: java concurrency queue

有一个名字,但我不知道它是什么,所以谷歌很难。

我正在寻找的东西是java并发实用程序,它是一对队列,生产者使用的“待处理”队列,以及消费者使用的“处理”队列,消费者可以在这里交换原子地排队。如果以这种方式使用(1个生产者线程,1个消费者线程),则各个队列不需要是线程安全的,只需要对它们的引用。

我知道我以前见过这个地方,我可以自己拼凑这样的东西,但如果它已经存在,我宁愿用它。

编辑我想我正在寻找的原语是一对可以原子交换的原子引用。 (&我可以自己添加队列。)


编辑2: @Alex Miller回答了一个唠叨的问题,即我在想什么但却记不起来了。然而,这并没有解决我的问题,因为它是一个线程障碍,我希望生产者不必阻止。

@pfossin关于交换对队列的引用的观点是一个很好的观点;我想要的是,消费者开始从队列中检索和处理项目的瞬间,所有这些队列项目必须完整,生产者之后不能添加任何项目;生产者现在必须将项目添加到另一个队列。因此配对/交换的原子引用集将无效。

(有点像是有2辆校车,其中一辆始终在等候乘客而另一辆总是把它们送到别处。一旦司机拉开,就是这样,你必须乘坐另一辆公共汽车。有引用允许生产者访问总线,即使它已经离开,这是不允许的。)

我认为我要做的是使用单个ConcurrentLinkedQueue并具有消费者添加到队列中的标记值。这允许有多个生产者,而不仅仅是1.为了让消费者处理队列中的批量项目,消费者等待队列中至少有一个项目,然后在末尾插入标记。排队,并删除项目,直到删除标记。然后消费者做批次之间的任何事情。这就是我想要的行为。

它不一定需要是一种有保障的非阻塞方法(锁定或synchronized方法是选项),但如果有一种简单的方法来构建它,那么它在我的应用程序中是首选。

3 个答案:

答案 0 :(得分:2)

答案 1 :(得分:2)

读取器/写入器锁定队列,可能是一个更好的主意。因为,否则你必须原子地复制到本地队列。

由于您有同步问题,如果您在读取/删除或写入时交换了引用。

RWLock将允许多个消费者/生产者。

有什么理由,为什么你要远离RWLocks?

与任何锁定一样,锁定应保持最短时间以防止饥饿。

或使用类似的东西来交换数据。每个线程都拥有自己的队列。

 class LockedQueue
 {
    private final List<Data>  q = new ArrayList<Data>();
    private final Lock lock = new ReentrantLock();

    public void get( List<Data> consumerQ ) {
        if( lock.tryLock() ) { try { consumerQ .addAll( q ); q.clear(); } finally { lock.unlock(); }}
    }
    public Data put( List<Data> producerQ ) {
        if( lock.tryLock() ) { try { return q.addAll( producerQ  ); producerQ .clear(); } finally { lock.unlock(); }}
    }
    public void clear() {
        lock.lock(); try { q.clear(); } finally { lock.unlock(); }
    }
 }

与消费者调用get(),空或在每个循环结束时和消费者调用put,添加这么多项目或时间后......或者

答案 2 :(得分:0)

没有像你描述的那样有双队列的数据结构,但concurrent utils有很多不同的队列可供选择来制作一个。

你描述的问题很常见,我也希望找到一个。也许在Java 1.7中。