4

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

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

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

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


编辑 2: @Alex Miller 回答了我在想但想不起来的问题。然而,这并不能解决我的问题,因为它是一个线程障碍,我希望生产者不必阻塞。

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

(这有点像如果有两辆校车,其中一辆总是在等乘客,另一辆总是在其他地方送他们。一旦司机离开,就是这样,你必须上另一辆公共汽车。有参考可以让即使总线已经离开,生产者也可以访问总线,这是不允许的。)

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

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

4

3 回答 3

2

交换器

于 2009-03-11T20:11:26.553 回答
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,在添加了这么多项目或时间或......

于 2009-03-11T20:14:59.383 回答
0

没有像您描述的那样具有双队列的数据结构,但是并发实用程序有很多不同的队列可供选择。

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

于 2009-03-11T19:38:09.207 回答