Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/loops/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 引发ConcurrentModificationException的ArrayList迭代器_Java_Loops_Arraylist_Concurrency_Iterator - Fatal编程技术网

Java 引发ConcurrentModificationException的ArrayList迭代器

Java 引发ConcurrentModificationException的ArrayList迭代器,java,loops,arraylist,concurrency,iterator,Java,Loops,Arraylist,Concurrency,Iterator,我有一个带有两个访问器方法和一个通知器的ArrayList。我的名单: private final List<WeakReference<LockListener>> listeners = new ArrayList<>(); private final List listeners=new ArrayList(); 所有订阅操作都使用此选项: public void subscribe(@NonNull LockListener listener) {

我有一个带有两个访问器方法和一个通知器的ArrayList。我的名单:

private final List<WeakReference<LockListener>> listeners = new ArrayList<>();
private final List 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();
        }
    }
}
public void subscribe(@NonNull LockListener){
for(Iterator it=listeners.Iterator();it.hasNext();){
//这个已经订阅了吗?
if(listener.equals(it.next().get())){
返回;
}
}
add(newweakreference(listener));
}
所有取消订阅操作都使用此选项:

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();
        }
    }
}
public void取消订阅(@NonNull LockListener listener){
if(listeners.isEmpty()){
返回;
}
for(Iterator it=listeners.Iterator();it.hasNext();){
WeakReference ref=it.next();
如果(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();
        }
    }
}
private void notifyListeners(){
if(listeners.isEmpty()){
返回;
}
Iterator it=listeners.Iterator();
while(it.hasNext()){
WeakReference ref=it.next();
if(ref==null | | ref.get()==null){
it.remove();
}否则{
ref.get().onLocked();
}
}
}
我在测试中看到,notifyListeners()中的it.next()偶尔会抛出ConcurrentModificationException。我猜这是由于订阅服务器方法中的listeners.add()造成的

我想我对迭代器有误解。我的假设是,对列表进行迭代可以保护我不受添加/删除操作引起的并发问题的影响

显然我错了。是否迭代器只是在更改正在迭代的集合时防止ConcurrentModificationException的一种保护?例如,在迭代时对列表调用remove()会引发错误,但调用它.remove()是安全的


在我的例子中,订阅在迭代的同一个列表上调用add()。我在这里的理解正确吗?

如果我正确地阅读了您的最后一句话,那么您示例中的三个方法将从多个线程并发调用。如果确实如此,那么这就是你的问题

ArrayList不是线程安全的。无论是直接修改还是使用迭代器修改,在没有额外同步的情况下并发修改它都会导致未定义的行为


您可以同步对列表的访问(例如,使三个方法同步),或者使用线程安全的集合类,如ConcurrentLinkedQue。对于后者,请务必阅读JavaDoc(特别是关于迭代器每周一致性的部分),以了解什么是有保证的,什么是没有保证的。

如果您阅读迭代器的文档,它将告诉您不能修改底层结构