Java 用于写时复制集合的迭代器

Java 用于写时复制集合的迭代器,java,Java,来自JCIP的摘要 写时复制集合的迭代器保留对 在迭代开始时和之后是当前的支持数组 这永远不会改变,它们只需短暂同步到 确保数组内容的可见性 写时复制集合返回的迭代器不会抛出 ConcurrentModificationException和返回的元素与 它们在迭代器创建时就已经存在了,不管 后续修改 查看下面的源代码: i、 esetArray(新元素)如方法中所示 其中getArray() 92 final Object[] More ...getArray() { 93

来自JCIP的摘要

写时复制集合的迭代器保留对 在迭代开始时和之后是当前的支持数组 这永远不会改变,它们只需短暂同步到 确保数组内容的可见性

写时复制集合返回的迭代器不会抛出 ConcurrentModificationException和返回的元素与 它们在迭代器创建时就已经存在了,不管 后续修改

查看下面的源代码:

i、 e
setArray(新元素)如方法中所示

其中getArray()

92      final Object[] More ...getArray() {
93          return array;
94      }
&setArray(…)

是否在此易失性阵列上执行操作

private volatile transient Object[] array;
显然,迭代器返回的是(if)已修改的数组,而不是在迭代过程开始时创建的数组

那么,作者的意思是什么-

返回元素,与使用迭代器时完全相同 创建,无论后续修改如何

由于返回的数组是易变的,因此保证反映对引用变量的任何更改

这与
volatile
语义无关。当调用
CoIterator
构造函数时(当创建迭代器时),将创建对数组的引用。创建数组的新副本并将其引用分配给
数组
字段将使迭代器的
快照
指向相同的旧引用

由于返回的数组是易变的,因此保证反映对引用变量的任何更改


这与
volatile
语义无关。当调用
CoIterator
构造函数时(当创建迭代器时),将创建对数组的引用。创建数组的新副本并将其引用分配给
数组
字段将保持迭代器的
快照
指向同一个旧引用。

假设您实例化了
CopyOnWriteArrayList
,现在
元素
正在引用数组:

元素->[0,1,2]

现在您创建了一个
协同迭代器
快照
正在引用相同的数组:

元素->[0,1,2][0,1,2]

元素->[0,1,3]


所以,
snapshot
仍然指向初始数组

假设您实例化了一个
CopyOnWriteArrayList
,现在
元素引用了一个数组:

元素->[0,1,2]

现在您创建了一个
协同迭代器
快照
正在引用相同的数组:

元素->[0,1,2][0,1,2]

元素->[0,1,3]


所以,
snapshot
仍然指向初始数组

您粘贴到此处的代码有以下几行(中间没有复制几行): Object[]elements=getArray(); Object[]newElements=Arrays.copyOf(elements,len); 新元素[索引]=元素

第1行引用支持此集合的现有数组。如果在更新集合之前尝试获取迭代器,则这是迭代器获取的数组(称为快照)

第2行是通过复制(因此是COW)创建的新数组,然后向其中添加新项,如第3行所示

然后将该新元素数组分配给volatile数组引用。迭代器已经在引用旧的快照数组,所以它甚至不知道正在更新的数组


希望这能解释

您粘贴到此处的代码有以下几行(中间没有复制几行): Object[]elements=getArray(); Object[]newElements=Arrays.copyOf(elements,len); 新元素[索引]=元素

第1行引用支持此集合的现有数组。如果在更新集合之前尝试获取迭代器,则这是迭代器获取的数组(称为快照)

第2行是通过复制(因此是COW)创建的新数组,然后向其中添加新项,如第3行所示

然后将该新元素数组分配给volatile数组引用。迭代器已经在引用旧的快照数组,所以它甚至不知道正在更新的数组


希望这能解释

我看了你在这里发布的代码,很明显,迭代器返回的是一个从未修改过的数组。@MarkoTopolnik:但同时,其他线程可以通过
set(int index,E element)对其进行清晰的修改。
“很明显,迭代器返回的是数组”Ehh,nooo。“显然”,迭代器使用的是在创建迭代器时获得的数组。列表的任何后续修改都将创建一个新数组,因此迭代器将不会看到这些更改。@ShirgillFarhanAnsari我看不到这方面的证据,而是看到一个新数组的修改,该数组随后被指定为“当前”数组。一旦分配,它就不会改变。我没有注意到你有任何冒犯。抱歉是不应该的。我看了你在这里发布的代码,很明显,迭代器返回的是一个从未修改过的数组。@MarkoTopolnik:但同时,其他线程可以通过
set(int index,E element)对其进行清晰的修改。
“显然,迭代器返回的是数组”Ehh,nooo。“显然”,迭代器使用的是在创建迭代器时获得的数组。列表的任何后续修改都将创建一个新数组,因此迭代器将不会看到这些更改。@ShirgillFarhanAnsari我看不到这方面的证据,而是看到一个新数组的修改,该数组随后被指定为“当前”数组。一旦分配,它就不会改变。我没有注意到你有任何冒犯。抱歉是不应该的。这是我写的-快照指向数组ret
92      final Object[] More ...getArray() {
93          return array;
94      }
final void More ...setArray(Object[] a) {
100         array = a;
101     }
private volatile transient Object[] array;