2017-01-18 27 views
1

有地图持有事件监听器通过类型键相同的事件列表不同的线程中删除的项目,可以的CopyOnWriteArrayList帮助允许从已经放在一个迭代器

func_1()将开始得到一个类型从listenerlist地图并迭代列表以与每个监听者一起处理事件。

当一个监听器完成其处理时,它会要求将其从监听器列表中移除。

由于侦听器处于迭代器中,因此将其从原始列表中删除将导致java.util.ConcurrentModificationExceptioniterator.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; 
       } 
      } 
     } 
} 
+0

应该不难测试,但'CopyOnWriteArrayList'保证从不抛出'ConcurrentModificationException'。 – shmosel

回答

0

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

如果事件过于频繁,则可能会造成代价高昂。

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

“2的CopyOnWriteArrayList 形成阵列的一个全新副本是过于昂贵的操作,在时间和内存开销方面,考虑为正常使用;开发人员往往求助于使用同步但是,这也是一个代价高昂的选择,因为每次迭代集合的内容时,都必须同步所有操作,包括读取和写入,以确保一致性。 这使成本结构向后读者正在阅读ArrayList,但很少有人正在修改它。 CopyOnWriteArrayList是解决这个问题的惊人小珠宝。 Javadoc将CopyOnWriteArrayList定义为“ArrayList的线程安全变体,其中所有可变操作(add,set等)都是通过创建数组的新副本来实现的。” 集合内部将其内容复制到新数组在进行任何修改时,读取数组内容的读者不会产生同步成本(因为他们从不使用可变数据)。 从本质上讲,CopyOnWriteArrayList对于ArrayList使我们失败的确切场景是理想的:对于JavaBean事件,通常是读取 - 很少写入集合,例如监听器。“

相关问题