java - 静态同步方法中的 ConcurrentModificationError
问题描述
我有一个包含一个字段和两个static synchronized
方法的类。该字段是一个映射,其键是整数,值是列表。其中一种方法用于在列表中添加新项目,另一种方法用于读取列表中的所有项目。我有多个线程来读取和写入map
. 我消除了代码中的一些细节,所以让我们假设密钥始终在地图中。
据我了解,只有一个线程可以进入其中一个write
或read
同时进入,因为它们都被声明为static synchronized
. 这意味着当一个线程正在写东西时,其他线程不能写或读,反之亦然。但是为什么ConcurrentModificationError
迭代器在列表 return by map.get(i)
at line上迭代时抛出了一个for(int item: map.get(i))
?谁能解释一下是什么原因?提前致谢!
class A {
private static Map<Integer, List<Integer>> map;
public static synchronized void write(int i, int item) {
map.get(i).add(item);
}
public static synchronized void read(int i) {
for(int item: map.get(i)) System.out.println(item);
}
}
解决方案
我认为,在您的代码中的某处,地图所包含的列表存在并发修改。我写了一个小代码,它抛出了相同的 ConcurrentModificationException:
public class A {
private static Map<Integer, List<Integer>> map = new HashMap<>();
public static synchronized void write(int i, int item) {
if (map.containsKey(i))
map.get(i).add(item);
else {
ArrayList<Integer> list = new ArrayList<>();
list.add(item);
map.put(i, list);
}
}
public static synchronized void read(int i) {
for (int item : map.get(i))
System.out.println(item);
}
public static void main(String[] args) {
Runnable writeAction = () -> A.write(1, 1);
Runnable readAction = () -> A.read(1);
Runnable modifyAction = () -> A.modifyList(1, 2);
ExecutorService service = Executors.newFixedThreadPool(4);
for (int i = 0; i < 1_000; i++) {
service.execute(writeAction);
service.execute(readAction);
service.execute(modifyAction);
}
service.shutdown();
}
/**
* not synchronized
* @param i
* @param item
*/
public static void modifyList(int i, int item) {
if (map.containsKey(i))
map.get(i).add(item);
else {
ArrayList<Integer> list = new ArrayList<>();
list.add(item);
map.put(i, list);
}
}
}
当池中的两个线程同时运行 modifyList() 和 read() 方法时,此代码肯定会引发异常。
因此,要么你的类中有一个不同步的方法,要么可能有一些 getter 返回原始列表的引用而不是它的副本(我的意思是转义引用)以及它返回到的任何方法 - 他们正在修改列表和同时。
推荐阅读
- gradle - gradle EAR 插件在通过 eclipse 构建时会忽略耳塞内容
- sql - sql查询添加原始查询中缺少的行
- mysql - 在查询结果中添加日期列
- android - 我可以在安卓上运行 zenbot 吗?
- c++ - 无法将结构注册为增强几何 3D 点
- r - 在 RStudio 中组织日期和时间
- python - 两个数据帧中短语的文本比较,并在匹配短语与序列和索引处获得输出
- touch - Fullpage.js - 在“带触控的笔记本电脑”上无法正常工作
- c - 如何在没有轮询的情况下判断 fb_var_screeninfo 是否更改
- node.js - 如何使用 Node.js 在本地主机上播放 IBM Watson Text To Speech 音频