使用 CopyOnWriteArrayList 的 foreach 会导致 java 中的 ConcurrentModificationException 吗?
Can using foreach of CopyOnWriteArrayList cause ConcurrentModificationException in java?
我在 CopyOnWriteArrayList
中查看 java 11 .foreach
方法的实现
public void forEach(Consumer<? super E> action) {
Objects.requireNonNull(action);
for (Object x : getArray()) {
@SuppressWarnings("unchecked") E e = (E) x;
action.accept(e);
}
}
我看到它只是在没有任何锁的情况下循环数组。
add()
或 remove()
可以与 foreach
同时执行给出 ConcurrentModificationException
吗?
与 iterator()
相比,foreach
似乎避免在写入时使用原始数组的副本并且它不使用锁。
Can using foreach
of CopyOnWriteArrayList
cause ConcurrentModificationException
in java?
没有。你可以从代码中看到它不会抛出 ConcurrentModificationException
:
public void forEach(Consumer<? super E> action) {
Objects.requireNonNull(action);
for (Object x : getArray()) {
@SuppressWarnings("unchecked") E e = (E) x;
action.accept(e);
}
}
注意 getArray()
调用不是复制数组。它是这样声明的:
private transient volatile Object[] array;
final Object[] getArray() {
return array;
}
(因为array
是volatile
,不需要锁来确保getArray()
returns是数组的当前版本。)
Can add()
or remove()
performed concurrently with foreach
give a ConcurrentModificationException
?
对这些方法的调用将导致使用更新创建新的后备数组。这是通过锁定 CopyOnWriteArrayList
完成的,然后替换数组。
与此同时,foreach()
调用将遍历 old 数组,就好像什么都没发生一样。
In contrast to iterator()
, foreach seems to avoid using the copy of original array on write and it uses no locks.
实际上,iterator()
的行为方式与 foreach
相同。它调用 getArray()
来获取当前支持数组。
public Iterator<E> iterator() {
return new COWIterator<E>(getArray(), 0);
}
如果您查看 COWIterator
class,它也不会抛出 ConcurrentModificationException
。
请注意,这都是在 javadocs 中指定的。
CopyOnWriteArrayList
状态的 javadoc:
"... the iterator is guaranteed not to throw ConcurrentModificationException
."
foreach
(在 Iterable
)状态的 javadoc:
"The default implementation behaves as if:"
for (T t : this)
action.accept(t);
使用 CopyOnWriteArrayList
提供的迭代器,不会抛出 ConcurrentModificationException
;见 1.
但是,有一个小问题。 CopyOnWriteArrayList
的子列表不是 CopyOnWriteArrayList
,它 可以 产生 ConcurrentModificationException
;见 CopyOnWriteArrayList throwing CurrentModificationException
我在 CopyOnWriteArrayList
.foreach
方法的实现
public void forEach(Consumer<? super E> action) {
Objects.requireNonNull(action);
for (Object x : getArray()) {
@SuppressWarnings("unchecked") E e = (E) x;
action.accept(e);
}
}
我看到它只是在没有任何锁的情况下循环数组。
add()
或 remove()
可以与 foreach
同时执行给出 ConcurrentModificationException
吗?
与 iterator()
相比,foreach
似乎避免在写入时使用原始数组的副本并且它不使用锁。
Can using
foreach
ofCopyOnWriteArrayList
causeConcurrentModificationException
in java?
没有。你可以从代码中看到它不会抛出 ConcurrentModificationException
:
public void forEach(Consumer<? super E> action) {
Objects.requireNonNull(action);
for (Object x : getArray()) {
@SuppressWarnings("unchecked") E e = (E) x;
action.accept(e);
}
}
注意 getArray()
调用不是复制数组。它是这样声明的:
private transient volatile Object[] array;
final Object[] getArray() {
return array;
}
(因为array
是volatile
,不需要锁来确保getArray()
returns是数组的当前版本。)
Can
add()
orremove()
performed concurrently withforeach
give aConcurrentModificationException
?
对这些方法的调用将导致使用更新创建新的后备数组。这是通过锁定 CopyOnWriteArrayList
完成的,然后替换数组。
与此同时,foreach()
调用将遍历 old 数组,就好像什么都没发生一样。
In contrast to
iterator()
, foreach seems to avoid using the copy of original array on write and it uses no locks.
实际上,iterator()
的行为方式与 foreach
相同。它调用 getArray()
来获取当前支持数组。
public Iterator<E> iterator() {
return new COWIterator<E>(getArray(), 0);
}
如果您查看 COWIterator
class,它也不会抛出 ConcurrentModificationException
。
请注意,这都是在 javadocs 中指定的。
CopyOnWriteArrayList
状态的 javadoc:"... the iterator is guaranteed not to throw
ConcurrentModificationException
."foreach
(在Iterable
)状态的 javadoc:"The default implementation behaves as if:"
for (T t : this) action.accept(t);
使用
CopyOnWriteArrayList
提供的迭代器,不会抛出ConcurrentModificationException
;见 1.
但是,有一个小问题。 CopyOnWriteArrayList
的子列表不是 CopyOnWriteArrayList
,它 可以 产生 ConcurrentModificationException
;见 CopyOnWriteArrayList throwing CurrentModificationException