可以CopyOnWriteArrayList帮助从不同线程中删除已放入迭代器中的项



有一个映射,按键的类型保存相同事件的事件侦听器列表

func_1()将开始从映射中获取一种类型的listenerlist,并迭代该列表以处理每个侦听器的事件。

当一个侦听器完成处理时,它将要求将其从映射中的侦听器列表中删除。

由于侦听器在迭代器中,从原始列表中删除它将导致iterator.previous()中的java.util.ConcurrentModificationException用于获取下一个侦听器。

问题是,如果使用CopyOnWriteArrayList复制侦听器列表,然后对其进行迭代器,因为它是列表的副本,所以当侦听器从其他线程中删除时,它还会抛出吗?

只是简单地复制一个普通列表而不是CopyOnWriteArrayList来进行迭代器,这有什么区别吗?

func_1(Event event) {
List<WeakReference<EventListener<Event>>> listenerlist = mEventMap.get(event.eventType);
/* instead of directly iterator on the listenerlist
ListIterator<WeakReference<EventListener<Event>>> listenerIterator = 
listenerlist.listIterator(listenerlist.size());
but making a CopyOnWriteArrayList first:
*/
List<WeakReference<EventListener<Event>>> listeners = 
new CopyOnWriteArrayList<>(listenerlist);
ListIterator<WeakReference<EventListener<Event>>> listenerIterator = 
listeners.listIterator(listeners.size());
while(listenerIterator.hasPrevious()){
WeakReference<EventListener<Event>> listenerItem =   
listenerIterator.previous();
//doing something
listenerItem.func_2(event);
}
}
EventListener::func_2(Event event){
//do something
//remove the type in the map
funct_3(EventListener.this);
}
funct_3(EventListener listener) {
List<WeakReference<EventListener<Event>>> listeners = 
mEventMap.get(listener.eventType);
if (listeners != null) {
Iterator<WeakReference<EventListener<Event>>> listenerIterator = 
listeners.iterator();
while (listenerIterator.hasNext()) {
WeakReference<EventListener<Event>> listenerItem = listenerIterator.next();
if (listenerItem.get() != null && listenerItem.get() == listener) {
listenerIterator.remove();
break;
}
}
}
}

进行了测试,但它没有抛出,因为它在列表的副本上迭代,而删除发生在原始列表上。

退一步说,如果活动来得太频繁,成本可能会很高。

-https://www.ibm.com/developerworks/library/j-5things4/

"2.CopyOnWriteArrayList从时间和内存开销的角度来看,制作数组的新副本是一项过于昂贵的操作,不适合普通使用;开发人员经常使用同步的ArrayList。然而,这也是一个代价高昂的选项,因为每次遍历集合的内容时,都必须同步所有操作,包括读写操作,以确保一致性。这将使成本结构倒退到许多读者正在阅读ArrayList但很少有人修改它的场景中。CopyOnWriteArrayList是解决这个问题的一颗神奇的小宝石。它的Javadoc将CopyOnWriteArrayList定义为"ArrayList的线程安全变体,其中所有可变操作(添加、设置等)都是通过制作数组的新副本来实现的。"该集合在进行任何修改时都会在内部将其内容复制到一个新的数组中,因此访问数组内容的读取器不会产生同步成本(因为它们从不对可变数据进行操作)。从本质上讲,CopyOnWriteArrayList非常适合ArrayList失败的情况:经常读取,很少写入的集合,如JavaBean事件的Listeners。">

最新更新