1

有一个地图按类型保存相同事件的事件监听器列表作为键,

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

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

因为侦听器位于迭代器中,将其从原始列表中删除将导致java.util.ConcurrentModificationException获取iterator.previous()下一个侦听器。

问题是如果使用 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;
                }
            }
        }
}
4

1 回答 1

0

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

缺点是,如果活动过于频繁,成本可能会很高。

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

集合在任何修改时都会在内部将其内容复制到新数组,因此访问数组内容的读取器不会产生同步成本(因为它们从不对可变数据进行操作)。从本质上讲,CopyOnWriteArrayList 非常适合 ArrayList 失败的确切场景:经常读取、很少写入的集合,例如 JavaBean 事件的侦听器。”

于 2017-01-18T13:36:31.603 回答