gpt4 book ai didi

java - 线程安全的 CopyOnWriteArrayList 反向迭代

转载 作者:搜寻专家 更新时间:2023-11-01 02:02:40 26 4
gpt4 key购买 nike

考虑以下代码片段:

private List<Listener<E>> listenerList = new CopyOnWriteArrayList<Listener<E>>();

public void addListener(Listener<E> listener) {
if (listener != null) {
listenerList.add(listener);
}
}

public void removeListener(Listener<E> listener) {
if (listener != null) {
listenerList.remove(listener);
}
}

protected final void fireChangedForward(Event<E> event) {
for (Listener<E> listener : listenerList) {
listener.changed(event);
}
}

protected final void fireChangedReversed(Event<E> event) {
final ListIterator<Listener<E>> li = listenerList.listIterator(listenerList.size());
while (li.hasPrevious()) {
li.previous().changed(event);
}
}

有一个可以修改和迭代的监听器列表。我认为前向迭代(参见方法#fireChangedForward)应该是安全的。问题是:反向迭代(参见方法#fireChangedReversed)在多线程环境中是否也安全?我对此表示怀疑,因为涉及两个调用:#size 和#listIterator。如果它不是线程安全的,那么在以下情况下实现#fireChangedReversed 的最有效方法是什么:

  • 优化遍历
  • 尽可能避免使用锁定
  • 避免使用 javax.swing.event.EventListenerList
  • 首选不使用第三方库的解决方案,例如可以用自己的代码实现

最佳答案

确实,listenerList.listIterator(listenerList.size()) 不是线程安全的,这正是您建议的原因:列表可能会在调用 size() 之间更改大小listIterator(),导致从迭代中遗漏一个元素,或者抛出 IndexOutOfBoundsException

处理此问题的最佳方法是在获取迭代器之前克隆 CopyOnWriteArrayList:

    CopyOnWriteArrayList<Listener<E>> listenerList = ... ;
@SuppressWarnings("unchecked")
List<Listener<E>> copy = (List<Listener<E>>)listenerList.clone();
ListIterator<Listener<E>> li = copy.listIterator(copy.size());

克隆对列表进行浅拷贝。特别是,克隆与原始数组共享内部数组。这在规范中并不完全明显,它只是说

Returns a shallow copy of this list. (The elements themselves are not copied.)

(当我读到这里时,我想“当然没有复制元素;这是一个浅拷贝!”这真正的意思是元素和包含它们的数组都没有被复制。)

这相当不方便,包括缺少 clone() 的协变覆盖,需要未经检查的转换。

JDK-6821196 中讨论了一些潜在的增强功能和 JDK-8149509 .前一个错误还链接到 discussion这个问题在并发兴趣邮件列表上。

关于java - 线程安全的 CopyOnWriteArrayList 反向迭代,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42045206/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com