【发布时间】:2016-04-27 19:27:50
【问题描述】:
是否有任何干净有效的方法来发展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.arraycopy 或Arrays.copy 类型的函数慢得多,而且有点冗长。
我可以交替使用反射来获取源的 array 字段,扩展它,并将新数组传递给 Atomic*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的构造函数中,非常难看。
有没有更快/更清洁的方法来做到这一点?
【问题讨论】:
-
您可以通过从旧数组链接到新数组来增长,以便消费者可以遍历。有关此想法的示例,请参见 JCTools 的 MpscChunkedArrayQueue。
-
@BenManes 是的,我想到了这个想法,但是内存使用量要高得多,因为我们需要将数组包装在链接中,并且逻辑有点复杂,因为我们需要维护一个近似的尾指针。就像单个数组一样工作正常,但我希望从这种方法中获得尽可能多的性能。
-
@Solomonoff'sSecret 假设一个对象数组,你不会在最后一个索引中存储转发链接吗?由于擦除,丑陋的演员阵容值得性能提升。大多数情况下,您将使用正确的尺寸,并且只在增长时支付罚金。您的另一个选择是在 VarHandles 到达之前使用 Unsafe。
-
@BenManes 没错,您可以将下一个链接存储在最后一个索引中。这是个好主意。对,擦除意味着无论如何都会发生强制转换。
标签: java performance concurrency java.util.concurrent