ArrayList同时读写造成java.util.ConcurrentModificationException异常
在ArrayList同时读写时,会造成java.util.ConcurrentModificationException异常。该读写包括同时调用ArrayList的add、remove、size、addAll、set、get等方法,都会报该异常。
该异常的本质是调用上述方法List中modCount就会变化,如果这个modCount和exceptedModCount不一致,就会抛出异常。具体的场景有以下几种:使用forEach遍历时删除元素、多线程同时读写。
那如何避免该问题呢?遍历时删除元素,不要使用forEach遍历即可。 foreach方式遍历元素的时候会生成iterator,然后使用iterator遍历。同时iterator会保存一个expectedModCount参数。该参数表示List中修改元素的次数。如果在遍历过程中删除元素,List中modCount就会变化,如果modCount和exceptedModCount不一致,就会抛出异常。
如果使用iterator的remove方法则会正常,因为iterator的remove方法会在内部调用List的remove方法,但是会修改excepedModCount的值,因此会正常运行。以下是使用遍历同时删除元素不报异常的实例:
1、倒序遍历 List ,如果找到元素,则使用 remove 方法进行移除:
List<String> list = new ArrayList<>(); list.add("第一代码"); list.add("知音简历"); list.add("免费简历"); list.add("简历模板"); list.add("免费范文"); for (int i = list.size() - 1; i > 0; i--) { if("简历模板".equals(list.get(i))){ list.remove(i); } } System.out.println(list);
2、使用 Iterator ,顺序向下,如果找到元素,则使用 remove 方法进行移除:
List<String> list = new ArrayList<>(); list.add("第一代码"); list.add("知音简历"); list.add("免费简历"); list.add("简历模板"); list.add("免费范文"); // 获取迭代器 Iterator<String> it = list.iterator(); while(it.hasNext()){ String str = it.next(); if("第一代码".equals(str)){ it.remove(); } } System.out.println(list);
3、正序遍历 List ,如果找到元素,则使用 remove 方法进行移除,然后进行索引自减:
List<String> list = new ArrayList<>(); list.add("第一代码"); list.add("知音简历"); list.add("免费简历"); list.add("简历模板"); list.add("免费范文"); for (int i = 0; i < list.size(); i++) { if("知音简历".equals(list.get(i))){ list.remove(i); i--; } } System.out.println(list);
4、使用jdk1.8新增的Stream流操作:
List<String> list = new ArrayList<>(); list.add("第一代码"); list.add("知音简历"); list.add("免费简历"); list.add("简历模板"); list.add("免费范文"); // 筛选出不是“第一代码” 的集合 list = list.stream().filter(e -> !"第一代码".equals(e)).collect(Collectors.toList()); System.out.println("method4|list=" + list);
以下是使用多线程读写不报异常的实例,可添加synchronized 同步锁防止异常:
List<String> list = new ArrayList<>(); synchronized (list) { list.add("第一代码"); list.add("知音简历"); list.add("免费简历"); list.add("简历模板"); list.add("免费范文"); System.out.println(list.get(0)); } synchronized (list) { for (int i = list.size() - 1; i > 0; i--) { if ("简历模板".equals(list.get(i))) { list.remove(i); } } System.out.println(list); }
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。