如何使数组易变?因为我已经明白,使数组变得不稳定是不安全的吗?
答案 0 :(得分:17)
声明一个数组volatile 不给它的字段提供volatile访问权限。你声明引用本身是易失性的,而不是它的元素。
换句话说,您宣布的是易变的元素,而不是一组易失性元素。
这里的解决方案是使用AtomicIntegerArray
以防你想要使用整数。
另一种方式(但有点难看)是每次编辑字段时重写对数组的引用。
你这样做:
arr = arr;
(正如我所说......丑陋)
答案 1 :(得分:7)
AtomicLongArray,AtomicIntegerArray,AtomicReferenceArray(java.util.concurrent.atomic)。
答案 2 :(得分:3)
编辑: java中的数组对象。如果您对该对象进行volatile的引用,则在交换对该数组的引用时使其对其他线程可见。 但是这不适用于数组值本身。
更好地了解java内存模型,实际上有可能在没有Atomic * Array的情况下绕过它。使用发生在之前的关系进行易失性读取和正常写入使得它成为可能:
如果线程A在之后写入一些非易失性的东西和一个易失性变量,那么线程B也可以保证看到易失性内容的变化,但前提是线程B读取了volatile变量第一。 也可以看看: Happens-before relationships with volatile fields and synchronized blocks in Java - and their impact on non-volatile variables?
对于数组,这意味着: 写入数组后,写入一些易失性状态变量(确保写入实际更改易失性状态变量!) 从数组中读取时,首先读取易失性状态变量,然后访问该数组。 易失性读取也应该使所有其他写入也可见,只要它们发生在之前。
OLD:
写自我引用arr=arr
实际上并没有帮助。
您编写数组arr
的地址,而不是字段arr[i]
的值。因此,您仍然不会获得arr[i]
(您想要的)的易失性属性,但仅限于存储地址arr
。
前面提到的Jeremy Manson的博文详细解释了它: http://jeremymanson.blogspot.com/2009/06/volatile-arrays-in-java.html
他最好的解决方案是使用Atomic * Arrays,即AtomicReferenceArray用于泛型类型(基本类型也有特殊形式)。我无法想象这是特别有效的,特别是当它获得你需要的更多属性时(原子性>> volatile)。
替代方案可以是指针结构,其中容器使用易失性指针字段。也没那么有效......
答案 3 :(得分:1)
如何?
static class Cell<T> {
volatile T elem;
}
private Cell<T>[] alloc(int size){
Cell<T>[] cells = (Cell<T>[]) (new Cell[size]);
return cells;
}
volatile Cell<T>[] arr;
Cell<T>[] newarr = alloc(16);
for (int i = 0; i < newarr.length; i++) {
newarr[i] = new Cell<>();
}
arr = newarr;
细胞也使内容易挥发。也只有在预分配单元格之后,才将新数组分配给volatile数组...虽然可以牺牲Cell的额外内存,但是它是可管理的