从其他问题中,我了解到易失性数组的元素不是易失性的。只有引用本身是易变的。
volatile[] int data;
Thread A: data[4] = 457;
Thread B: System.out.println(data[4]);
此处,线程B可能永远不会看到更新的值。
我有哪些选择/替代方案可以达到同样的目的?我想避免同步数组,因为它几乎不会被改变。但是,有些线程正在阅读它。同步它很可能会降低吞吐量,这在本例中非常重要。
我唯一的选择是写入时复制数据结构吗?也就是说,将数组复制到一个新数组中,然后更新数组引用。
还有其他选择吗?我在某处读到将数组封装成一个类(只有一个成员,数组)实现同样的目的,但我怀疑这是真的。我看不出这可能会有什么帮助。
请注意我的目标JVM是1.4。这意味着我无法使用java.util.concurrent
包。
--------------编辑编辑编辑--------------
在Java volatile array?中我读到重新分配数组引用实现了波动性语义。这应该给出正确的结果:
volatile[] int data;
Thread A: data[4] = 457;
Thread A: data = data;
Thread B: System.out.println(data[4]);
这对旧版JVM有效吗?
答案 0 :(得分:1)
数组标记为volatile,即只将引用标记为volatile。数组本身的元素根本不继承volatile关键字的内存可见性语义。
我可以建议您自己构建一个AtomicIntergerArray
课程。您可以在哪里保留final int[] data
个推荐并正确同步。
另请查看AtomicIntergerArray
implementation code。
否则您可以使用Backport api的AtomicIntegerArray
。
该项目旨在提供一个并发库,该库在当前使用的所有Java平台上都具有无与伦比的性能,允许开发完全可移植的并发应用程序。更确切地说,traget范围是Java 1.3及更高版本,如果为Java 1.2提供,则会提供一些有限的支持。
答案 1 :(得分: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);
答案 2 :(得分:1)
使用arr=arr
管理Java来重写数组的存储地址(数组也是Java中的对象)。数组字段arr[i]
没有获得volatile属性。
在某些情况下,arr=arr
可能会因未知原因而起作用,但它并不会让您安全起见。
如果您想保持安全,请使用Atomic*Array
内容。是的,额外的原子性是昂贵的,但我想如果你考虑访问时间和存储空间,它比链接结构更好。
如果要避免全局锁定,可以考虑将数组拆分为子集。这使得锁只影响子集,并且您仍然保持所有值的波动性。
我分享你的问题,最好的选择是Atomic*Arrays
。