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

标签 java android copyonwritearraylist

拥有一个映射,按类型作为键保存同一事件的事件监听器列表,

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

当一个监听器完成处理后,它会要求将其从 map 的监听器列表中删除。

由于监听器位于迭代器中,因此从原始列表中删除它会导致 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;
                }
            }
        }
}

最佳答案

进行了测试,它不会抛出异常,因为它是在列表的副本上迭代,而删除发生在原始列表上。

缺点是如果 Activity 发生得太频繁,成本可能会很高。

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

"2.CopyOnWriteArrayList 就时间和内存开销而言,制作数组的新副本是一项过于昂贵的操作,无法考虑用于普通用途;开发人员经常使用同步的 ArrayList 来代替。然而,这也是一个成本高昂的选择,因为每次迭代集合的内容时,都必须同步所有操作(包括读取和写入)以确保一致性。 对于大量读者正在阅读 ArrayList 但很少有人修改它的情况,这使得成本结构向后倾斜。 CopyOnWriteArrayList 是解决这个问题的神奇小 gem 。它的 Javadoc 将 CopyOnWriteArrayList 定义为“ArrayList 的线程安全变体,其中所有可变操作(添加、设置等)都是通过制作数组的新副本来实现的”。 进行任何修改时,集合都会在内部将其内容复制到新数组,因此访问数组内容的读取器不会产生同步成本(因为它们从不操作可变数据)。 从本质上讲,CopyOnWriteArrayList 非常适合 ArrayList 无法满足我们的具体场景:经常读取、很少写入的集合,例如 JavaBean 事件的监听器。”

关于java - CopyOnWriteArrayList 可以帮助允许从已放入迭代器的不同线程中删除项目,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41710032/

相关文章:

java - Idea 中的 Tomcat。 war 爆炸 : Server is not connected. 部署不可用

java - 当小数为 0 时转换 DecimalFormat.parse() 的结果时出现 ClassCastException

java - 与 MongoDB 相比,使用 Java 驱动程序的 Cassandra Bulk-Write 性能非常糟糕

java - WebSphere类加载器和tomcat中的类加载器有什么不同吗?

java - android反射方法调用——什么是接收者

java - 迭代器、列表迭代器和 CopyOnWriteArrayList 之间的区别

java - 在 Android 中以编程方式更改 LinearLayout 从顶部(默认从底部)的高度 (Java)

Java套接字一直卡住

java - CopyOnWriteArrayList/ConcurrentHashMap内部如何处理Concurrent修改异常?

java - CopyOnWriteArrayList 仅适用于迭代,不适用于随机访问读取