我有一個ArrayList有兩個訪問器方法和一個通知器。我認爲:ArrayList迭代器拋出ConcurrentModificationException
private final List<WeakReference<LockListener>> listeners = new ArrayList<>();
所有訂閱操作使用:
public void subscribe(@NonNull LockListener listener) {
for (Iterator<WeakReference<LockListener>> it = listeners.iterator(); it.hasNext();) {
// has this one already subscribed?
if (listener.equals(it.next().get())) {
return;
}
}
listeners.add(new WeakReference<>(listener));
}
所有退訂操作使用:
public void unsubscribe(@NonNull LockListener listener) {
if (listeners.isEmpty()) {
return;
}
for (Iterator<WeakReference<LockListener>> it = listeners.iterator(); it.hasNext();) {
WeakReference<LockListener> ref = it.next();
if (ref == null || ref.get() == null || listener.equals(ref.get())) {
it.remove();
}
}
}
,並在通告:
private void notifyListeners() {
if (listeners.isEmpty()) {
return;
}
Iterator<WeakReference<LockListener>> it = listeners.iterator();
while (it.hasNext()) {
WeakReference<LockListener> ref = it.next();
if (ref == null || ref.get() == null) {
it.remove();
} else {
ref.get().onLocked();
}
}
}
我」什麼在我的測試中看到的是it.next()in n otifyListeners()偶爾會引發ConcurrentModificationException。我的猜測是這是由訂閱者方法中的listeners.add()引起的。
我想我對這裏的迭代器有一個誤解。我假設迭代列表可以保護我免受由添加/刪除操作引起的併發問題的困擾。
顯然我錯了。是否迭代器只是在更改要迭代的集合時防止發生ConcurrentModificationException?例如,在迭代時調用列表中的remove()會引發錯誤,但調用它.remove()是安全的。
在我的情況下,訂閱調用add()在同一個列表中,因爲它正在迭代。我的理解是否正確?
如果你閱讀了迭代器的文檔,它會告訴你,你不能修改底層結構 – efekctive