为什么我使用同步列表并仍然得到 ConcurrentModificationException

Why i used synchronized list and still get ConcurrentModificationException

我在 I used synchronized list, and i still get ConcurrentModificationException 中找到了同样的问题,但没有找到正确答案。

这是我定义 synchronized 列表的方式:

private List<ActionItemClickListener> actionItemClickListeners = Collections.synchronizedList(new ArrayList<ActionItemClickListener>());

下面是我的使用方式:

@Override
public void onBackPressed() {
    boolean isConsume = false;
    synchronized (actionItemClickListeners) {
        //ConcurrentModificationException occur here
        for (ActionItemClickListener listener : actionItemClickListeners) {
            isConsume = isConsume | listener.onSystemBackPressed();
        }
    }
    if(!isConsume) {
        pendingFragment = null;
        pendingTag = null;
        currentFragmentTag = null;
        super.onBackPressed();
    }
}
public void addActionItemClickListener(ActionItemClickListener listener) {
        synchronized (actionItemClickListeners) {
            if (listener != null)
                actionItemClickListeners.add(listener);
        }
}

public void removeActionItemClickListener(ActionItemClickListener listener) {
        synchronized (actionItemClickListeners) {
            if (listener != null)
                actionItemClickListeners.remove(listener);
        }
}

为什么我仍然收到 ConcurrentModificationException???

您的 ConcurrentModificationException 不是线程问题。抛出它是因为您在迭代列表时正在修改列表。

for (ActionItemClickListener listener : actionItemClickListeners) {
    isConsume = isConsume | listener.onSystemBackPressed();
}

问题是 listener.onSystemBackPressed(); 正在调用 removeActionItemClickListener,它试图更改您正在迭代的 actionItemClickListeners。尝试更改您正在迭代的列表将导致 ConcurrentModificationException

如何修复

没有看到你的其余代码,我只能猜测如何解决这个问题,但你可以使用 iterator.next()iterator.hasNext()iterator.remove() 循环和删除听众,分别。你要么需要通过 onSystemBackPressed()removeActionItemClickListener 传递 iterator,这有点难看,要么让 onSystemBackPressed() return 一个布尔值指示它是否应该删除侦听器。

final Iterator<String> iterator = actionItemClickListeners.iterator();
while (iterator.hasNext()) {
    final String listener = iterator.next();
    final boolean removeListener = listener.onSystemBackPressed();
    if (removeListener) {
        iterator.remove();
    }
    isConsume = isConsume | removeListener;
}

不幸的是,您似乎将 onSystemBackPressed() 的 return 值用于其他用途,因此这可能也不起作用。