我试图准确理解元素可见性如何在java中的数组上起作用。
鉴于课程:
class IntList {
private final int[] array;
public IntList(int[] array) {
this.array = array;
}
public int[] readElements() {
return Arrays.copyof(this.array, this.array.length);
}
}
以及用于创建实例的以下方法体:
int[] array = new int[length];
fillArrayWithRandomData(array); // puts data into the array from arbitrary source
return new IntList(array);
我想知道IntList
中的元素是否可以保证其他获取对返回的IntList
的引用的线程可见?
我确信数组的参考将是可见的,因为它是最终的,但我似乎无法保证数组中的元素也是可见的。
注意:IntList
类没有允许修改数组的方法,并且数组引用没有发布到任何其他对象,我只是想知道构造后的可见性。
修改:抱歉,在我的实际实施中,我的课程未被调用String
。我将班级名称更改为IntList
,因为似乎有太多的混淆。
修改 我将在这里提出的最终答案是肯定的,这些要素是可见的 @MikeClark找到了JLS答案: JLS§17.5“最终字段的使用模型很简单:在该对象的构造函数中设置对象的最终字段;并且不要在另一个线程可以在对象之前看到它的地方写入正在构造的对象的引用构造函数已完成。如果遵循此规则,那么当另一个线程看到该对象时,该线程将始终看到该对象的最终字段的正确构造版本。它还将看到那些最终字段引用的任何对象或数组的版本至少与最终字段一样是最新的。“
再次感谢!
答案 0 :(得分:2)
因为你在构造函数中填充数组然后是,所以对new String(int[] array)
的任何调用都会在返回时初始化数组。 final
关键字还可以保证在分配时对array
参数的最新更改可见。
答案 1 :(得分:0)
我发现这非常有帮助http://jeremymanson.blogspot.ch/2009/06/volatile-arrays-in-java.html 所以基本上一切都发生在易失性读取保证被其他线程看到之前。所以有一些黑客可以实现它。 另外,jaa提供本机AtomicReference / Long / Integer / ...数组支持。这将确保其他线程可以看到更新。
答案 2 :(得分:-2)
许多不同的概念似乎在你的问题中混淆了。
final
彼此无关private
变量在类之外对任何其他代码都不可见,无论它是否是最终的final
数组仍然可以更改其元素。它只是对数组本身的引用final
。构建IntList
对象时(顺便说一下,感谢您更改名称),如下所示:
public IntList(int[] array) {
this.array = array;
}
内部this.array
字段引用传递给构造函数的相同数组对象。仍然可以从String
类外部修改数组:
int[] array = {1, 2, 3};
IntList list = new IntList(array);
System.out.println(Arrays.toString(list.readElements()); // prints [1, 2, 3]
array[1] = 0;
System.out.println(Arrays.toString(list.readElements()); // prints [1, 0, 3]
您可以通过在构造函数中创建数组的副本来隔离您的类:
public IntList(int[] array) {
this.array = Arrays.copyOf(array, array.length);
}