问题解决: java.util.ConcurrentModificationException问题描述原因分析解决办法小结

问题描述

在H5性能测试平台系统的开发过程中,客户端调用服务端API,写入性能数据的时候,报了如下错误:

java.util.ConcurrentModificationException at 
java.util.ArrayList$ArrayListIterator.next(ArrayList.java:573)

错误代码:

    /**
     * 记录性能数据,写入server的数据库中
     *
     * @param requestResources
     */

    private void recordPerfData(List<HashMap<String, String>> requestResources) {
        Log.i("TAGH5", "requestResources=" + JSON.toJSONString(requestResources));
        for (HashMap<String, String> map : requestResources) {
            Log.i("TAGH5", "map=" + JSON.toJSONString(map));
            callWriteRequestResourceHttpApi(map);
        }
    }

原因分析

foreach循环,在使用iterator.hasNext()操作迭代器的时候,如果此时迭代的对象发生改变,比如插入了新数据,或者有数据被删除。此时,调用迭代器取数据ArrayListIterator.next(),会报上面的异常。

所以,涉及集合类的多线程的场景的操作的时候,要小心。

解决办法

  1. 通过Iterator修改Hashtable
while(it.hasNext()) {
Object ele = it.next();
            it.remove();
}
  1. 手动给Iterator遍历代码加锁,给修改HashMap的代码加锁。
  2. 使用CopyOnWriteArrayList

CopyOnWriteArrayList是java.util.concurrent包中的一个List的实现类。

CopyOnWrite的意思是在写时拷贝,也就是如果需要对CopyOnWriteArrayList的内容进行改变,首先会拷贝一份新的List并且在新的List上进行修改,最后将原List的引用指向新的List。

使用CopyOnWriteArrayList可以线程安全地遍历,因为如果另外一个线程在遍历的时候修改List的话,实际上会拷贝出一个新的List上修改,而不影响当前正在被遍历的List。

上面的报错代码修改如下:

recordPerfData(CopyOnWriteArrayList<HashMap<String, String>> requestResources)
  1. 如果是HashMap使用“ConcurrentHashMap”替换HashMap,ConcurrentHashMap会自己检查修改操作,对其加锁,也可针对插入操作。
import java.util.concurrent.*;

小结

遍历List的同时操作List会发生异常:

java.util.ConcurrentModificationException

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Charlie's Road

Swift算法俱乐部:Swift队列数据结构(Queue)

翻译自raywenderlich网站iOS教程Swift Algorithm Club系列

18820
来自专栏Hongten

java开发_double精度丢失的问题总结

=============================================================

11040
来自专栏专注 Java 基础分享

并发容器之写时拷贝的 List 和 Set

对于一个对象来说,我们为了保证它的并发性,通常会选择使用声明式加锁方式交由我们的 Java 虚拟机来完成自动的加锁和释放锁的操作,例如我们的 synchroni...

22960
来自专栏博岩Java大讲堂

Java集合--线程安全(CopyOnWrite机制)

34340
来自专栏Android相关

X86 Assemble指令--MOVS指令簇

该指令簇包括: MOVS mem16,mem16:显式指定源操作数与目的操作数 MOVSB:每次移动一个字节 MOVSW:每次移动一个字 MOVSD:每...

15620
来自专栏一个会写诗的程序员的博客

13.13 java.util.ConcurrentModificationException13.13 java.util.ConcurrentModificationException问题描述原因

在H5性能测试平台系统的开发过程中,客户端调用服务端API,写入性能数据的时候,报了如下错误:

8730
来自专栏尾尾部落

[剑指offer] 求1+2+3+…+n

求1+2+3+…+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。

9220
来自专栏老马说编程

(73) 并发容器 - 写时拷贝的List和Set / 计算机程序的思维逻辑

本节以及接下来的几节,我们探讨Java并发包中的容器类。本节先介绍两个简单的类CopyOnWriteArrayList和CopyOnWriteArraySet,...

20660
来自专栏尾尾部落

[剑指offer] 表示数值的字符串

请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串”+100″,”5e2″,”-123″,”3.1416″和”-1E-16″都表示数值。 ...

12020
来自专栏学习力

《Java从入门到放弃》JavaSE篇:练习——单身狗租赁系统(数组版)

23960

扫码关注云+社区

领取腾讯云代金券