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

时间:2017-01-18 01:37:25

标签: java android copyonwritearraylist

拥有一个map,按类型为键,保存相同事件的eventlisteners列表,

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

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

由于侦听器位于迭代器中,并且从原始列表中删除它将导致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;
                }
            }
        }
}

1 个答案:

答案 0 :(得分:0)

测试并没有抛出,因为它正在迭代列表的副本,而删除发生在原始列表中。

如果事件经常发生,退款可能会很昂贵。

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

&#34; 2。的CopyOnWriteArrayList 在时间和内存开销方面,制作一个新的数组副本是一项非常昂贵的操作,需要考虑普通使用;开发人员经常使用同步的ArrayList。然而,这也是一个代价高昂的选择,因为每次迭代集合的内容时,都必须同步所有操作,包括读取和写入,以确保一致性。 这使得成本结构落后于许多读者正在读取ArrayList但很少有人正在修改它的情况。 CopyOnWriteArrayList是解决这个问题的神奇小珠宝。它的Javadoc将CopyOnWriteArrayList定义为ArrayList的&#34;线程安全变体,其中所有的变异操作(添加,设置等)都是通过制作数组的新副本来实现的。&#34; 在任何修改时,集合在内部将其内容复制到新阵列,因此访问阵列内容的读者不会产生同步成本(因为他们永远不会对可变数据进行操作)。 从本质上讲,CopyOnWriteArrayList非常适合ArrayList使我们失败的确切场景:通常读取,很少写入集合,例如JavaBean事件的监听器。&#34;