3

从其他问题中,我了解到 volatile 数组的元素不是 volatile。只有引用本身是易变的。

volatile[] int data;

Thread A: data[4] = 457;
Thread B: System.out.println(data[4]);

在这里,线程 B 可能永远不会看到更新的值。

我必须使用哪些选项/替代方案来实现相同的目标?我想避免必须同步数组,因为它几乎从未改变过。但是,一些线程正在阅读它。同步它很可能会降低吞吐量,这在本例中非常重要。

我唯一的选择是写时复制数据结构吗?也就是说,将数组复制到一个新数组中,然后更新数组引用。

还有其他选择吗?我在某处读到将数组封装到一个类中(只有一个成员,数组)实现了同样的事情,但我怀疑这是真的。我看不出这有什么帮助。

请注意,我的目标 JVM 是 1.4。这意味着我不能使用这个java.util.concurrent包。

-------------- 编辑编辑编辑 --------------

Java 易失性数组中?我读到重新分配数组引用可以实现波动语义。这应该给出正确的结果:

volatile[] int data;

Thread A: data[4] = 457;
Thread A: data = data;
Thread B: System.out.println(data[4]);

这在较旧的 JVM 上有效吗?

4

3 回答 3

1

数组被标记为 volatile,即只有引用被标记为 volatile。数组本身的元素根本不继承 volatile 关键字的内存可见性语义。

我可以建议AtomicIntergerArray您自己建立一个课程。您可以在哪里保留final int[] data参考并正确同步它。

还要看看AtomicIntergerArray 实现代码

否则您可以使用Backport apiAtomicIntegerArray.

该项目旨在提供一个并发库,该库可在当前使用的所有 Java 平台上以不折不扣的性能工作,从而允许开发完全可移植的并发应用程序。更准确地说,traget 范围是 Java 1.3 及更高版本,如果为 Java 1.2 提供一些有限的支持。

于 2013-04-01T08:29:28.930 回答
1

只需使用包装器:

class VolatileInt{
    volatile int value;
}

VolatileInt[] create(int size){
    VolatileInt[] array = new VolatileInt[size];
    for(int k=0;k<size;k++)
        array[k]=new VolatileInt();
    return array; 
}

VolatileInt[] array = create(10);
于 2014-10-12T07:59:50.080 回答
1

使用arr=arrmanages Java重写数组的存储地址(数组在Java中也是对象)。数组字段arr[i]不会获得 volatile 属性。

在某些情况下,arr=arr可能会因为未知原因而起作用,但它不会让您安全。

如果您想保持安全,请使用这些Atomic*Array东西。是的,额外的原子性是昂贵的,但我想如果你考虑访问时间和存储空间,它比链接结构更好。

如果要避免全局锁,可以考虑将数组拆分为子集。这使得锁只影响一个子集,并且您仍然保持所有值的波动性。

我分享你的问题,最好的选择是Atomic*Arrays

于 2017-08-24T14:01:38.863 回答