【发布时间】:2011-07-07 14:43:59
【问题描述】:
如何使数组易失?因为据我了解,使数组易失是不安全的?
【问题讨论】:
如何使数组易失?因为据我了解,使数组易失是不安全的?
【问题讨论】:
编辑: 数组是java中的对象。如果您使对该对象的引用变为易失性,则如果您交换对数组的引用,则使其对其他线程可见。 但是,这不适用于数组值本身。
为了更好地理解 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?
对于数组,这意味着: 写入数组后,写入一些 volatile 状态变量(确保写入实际上更改了 volatile 状态变量!) 从数组中读取时,先读取 volatile 状态变量,然后再访问数组。 volatile 读取应该使所有其他写入也可见,只要它们发生在之前。
旧:
编写自我参考 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)。
另一种可能是容器使用易失指针字段的指针结构。也没有那么高效...
【讨论】:
将数组声明为 volatile 并不授予对其字段的 volatile 访问权限。您是在声明引用本身是 volatile,而不是它的元素。
换句话说,您声明的是易失性元素集,而不是易失性元素集。
这里的解决方案是使用AtomicIntegerArray,以防您想使用整数。另一种方法(但有点难看)是每次编辑字段时重写对数组的引用。
你这样做:
arr = arr;
(正如我所说的......丑陋)
【讨论】:
volatile 是关于保证发生前的关系。
这个怎么样:
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;
单元格也会使内容不稳定。我也仅在预先分配单元后才将新数组分配给易失性数组...存在 Cell 额外内存的权衡,但它是可管理的
【讨论】:
AtomicLongArray、AtomicIntegerArray、AtomicReferenceArray (java.util.concurrent.atomic)。
【讨论】: