2016-04-27 65 views
1

有什么清洁和有效的方式来种植Atomic(Double|Integer|Long|Reference)Array?在我的特殊情况下,复制期间没有并发写入。一个显而易见的方法来创建一个新的和源阵列复制到目标数组中的一个循环:高效增长的原子阵列

Atomic*Array dest = new Atomic*Array(newSize); 
for (int i = 0, len = src.length(); i < len; ++i) 
    dest.set(i, src.get(i)); 

该代码很可能不是System.arraycopyArrays.copy类型的函数慢得多,也有点冗长。

我可以交替使用反射来获取源的array领域,扩展它,而新的数组传递到原子* Array构造:

try { 
    Field arrayField = Atomic*Array.class.getDeclaredField("array"); 
    arrayField.setAccessible(true); 
    ArrayType srcArray = (ArrayType)arrayField.get(src); 
    Atomic*Array dest = new Atomic*Array(Arrays.copyOf(srcArray, newLength)); 
} catch (IllegalAccessException | NoSuchFieldException e) { 
    throw new AssertionError(e); 
} 

但是这个代码有问题,太:这取决于执行的Atomic*Array类,使数组的两个副本 - 一个在Arrays.copy和一个在dest的构造函数中,并且非常难看。

有没有更快/更干净的方法来做到这一点?

+0

相关:http://stackoverflow.com/questions/9408112/get-the-array-from-an-atomiclongarray –

+0

你可以通过链接从旧到新的数组,以便消费者可以遍历。有关此想法的示例,请参阅JCTools的[MpscChunkedArrayQueue](https://github.com/JCTools/JCTools/blob/master/jctools-core/src/main/java/org/jctools/queues/MpscChunkedArrayQueue.java)。 –

+0

@BenManes是的,我想到了这个想法,但是由于我们需要在链接中包装数组,因此内存使用量要高得多,而且逻辑稍微复杂一点,因为我们需要维护一个近似的尾指针。正如事情正在一个单一的阵列正常工作,但我想尽可能多的表现这种方法尽可能。 –

回答

1

我很担心我会让你失望的:没有办法如何批量复制Atomic*Array

看看javadoc,没有一种方法可以给你一次以上的单个元素。即使使用原始数组,您也可以传递给AtomicIntegerArray构造函数,这将有助于 - 该类在内部创建副本。

AtomicIntegerArray源代码,使用反射可以工作 - 类不会做任何特殊的array字段。不过,我不会。它不仅是不安全的,而且反射会给你一些你试图避免的性能损失。

如果您的目标是增加阵列,您可能需要查看LinkedBlockingQueueCopyOnWriteArrayList,具体取决于您的使用情况。

我已经跑了几次这个问题,我们总是找到一种方式,最终没有Atomic*Array

+0

谢谢。我的目标是实现一个非常有效的,非阻塞的仅附加列表。但不幸的是'LinkedBlockingQueue'和'CopyOnWriteArrayList'都不能满足我的需求:前者为节点使用太多的内存,而后者效率极低。事实上,标准库中的集合都不符合我的要求。 –

+0

太糟糕了,你添加了“非阻塞”的要求,否则你也可以用旧的'synchronized'做:) – Mifeet

+0

Right,'Collections.synchronizedList(new ArrayList <>())'会工作,但非阻塞是因为绝大多数时间没有争用,因此速度明显更快(即使通过循环复制增长)。 –