2012-02-04 89 views
2

我想知道AtomicReferenceArray是否可以用作ConcurrentLinkedQueue的替代品(如果有人可以使用有界结构)。AtomicReferenceArray的工作原理

目前,我有这样的:

ConcurrentLinkedQueue<Object[]> queue = new ConcurrentLinkedQueue<Object[]>(); 

public void store(Price price, Instrument instrument, Object[] formats){ 
    Object[] elements = {price, instrument, formats}; 
    queue.offer(elements); 
} 

商店(..)是由多个线程调用。

我也有一个消费者线程,它定期唤醒并消耗这些元素。

private class Consumer implements Runnable{ 

@Override 
public void run(){ 

List<Object[]> holder = drain(queue); 
for(Object[] elements : holder){ 
    for(Object e : elements){ 
     //process ... 
    } 
} 

private final List<Object[]> drain(){ 
//... 
} 

} 

我可以用ConcurrentLinkedQueue替换AtomicReferenceArray并仍然保持线程安全性方面吗?

具体来说,原子地存储元素并建立“之前发生”关系,以便消费者线程看到不同线程存储的所有元素?

我尝试阅读AtomicReferenceArray的源代码,但仍然不能确定。

干杯

+0

你在'ConcurrentLinkedQueue'中得到了'store'方法吗? – 2012-02-05 18:39:41

+0

抱歉,您想通过此开关获得什么? – 2012-02-05 18:44:10

+0

@pavelrappo对不起,应该是“offer”。我没有在这里复制我的实际代码,而是死记录它的一小部分。 – CaptainHastings 2012-02-06 01:54:38

回答

1

AtomicReferenceArray可以用作无锁单消费者/多生产者环形缓冲区。几个月前我实施了experimenting并有一个工作原型。优点是减少了垃圾创建,更好的缓存局部性,并且由于变得更简单而在未满时性能更好。缺点是缺乏严格的fifo语义,而当缓冲区已满时,由于制作者必须等待发生漏失,所以性能较差。这可以通过回落到ConcurrentLinkedQueue来缓解,以避免摊位。

生产者必须看到发生之前的边缘,以便他们获得一个独特的插槽。但是,由于只需要一名消费者,因此可能会推迟到排水完成。在我的使用中,流失是通过线程分摊的,所以消费者是通过成功获取try-lock来选择的。该锁的发布提供了边缘,允许阵列更新在临界区内使用延迟集。

我只会在性能高度调整的特殊场景中使用这种方法。在我的使用中,它作为缓存的内部实现细节很有意义。不过,我一般不会使用它。

+0

感谢Ben的回应和代码。 – CaptainHastings 2012-02-06 02:02:40

+0

我认为#store()意思是#add(),但后来你说过#offer()。如果您可以容忍由于已满而不被接受的报价,那么您可以安全地简化示例代码。 – 2012-02-06 22:57:04

1

我想知道如果AtomicReferenceArray可以作为的ConcurrentLinkedQueue更换(如果能有界结构活)。

基本上没有。

虽然对数组元素的单独更新是以原子方式进行的,但这对于队列来说是不够的。您还需要跟踪队列头部和尾部的位置,并且除非有一些额外的锁定/同步正在进行,否则您无法使用队列单元读/写自动执行此操作。

(这是一个独立的AtomicReferenceArray内部运作,问题很简单,就是API将无法为您提供您需要在单个原子操作来更新两件事情的功能。)