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

13.13 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 条评论
登录 后参与评论

相关文章

来自专栏编码小白

ofbiz实体引擎(四) ModelReader的作用

public class ModelReader implements Serializable { public static final Stri...

2838
来自专栏学习力

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

2356
来自专栏aCloudDeveloper

经典排序之 堆排序

Author: bakari  Date: 2012.7.30 排序算法有很多种,每一种在不同的情况下都占有一席之地。关于排序算法我分“经典排序之”系列分别述之...

1948
来自专栏尾尾部落

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

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

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

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

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

2206
来自专栏IT笔记

读取资源文件的四种方法

package com.action; import java.io.InputStream; import java.util.Locale; import...

4036
来自专栏尾尾部落

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

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

1152
来自专栏Java后端技术栈

Redis常见的5种不同的数据类型详解

Redis除了可以存储键还可以存储常见的5种数据类型,分别是:String、List、Set、Hash、ZSet。对于Redis的命令有一部分是可以公用的,但是...

981
来自专栏liulun

EntityFramework附加实体

//0.0创建修改的 实体对象 Models.BlogArticle model = new BlogArticle(); model.AId = 12; mo...

2239
来自专栏编程之旅

数据结构——队列

我们在使用手机的时候,偶尔都会碰到过卡住的时候,比如一个地方怎么点都没有用,屏幕也卡住不显示其他东西,但当你把卡住的App关闭掉之后,手机的操作显示就又恢复正常...

1741

扫码关注云+社区

领取腾讯云代金券