Java Collections.synchronized映射是否使迭代器线程安全

Java Collections.synchronized映射是否使迭代器线程安全,java,dictionary,iterator,synchronized,concurrentmodification,Java,Dictionary,Iterator,Synchronized,Concurrentmodification,系统中有两个线程。一个是读线程,另一个是写线程 使用以下代码同步映射 Map<String,ArrayList<String>> m = Collections.synchronizedMap(new HashMap<String,ArrayList<String>()) mapm=Collections.synchronizedMap(新的HashMap可能是这样的。这样做不安全 当用户迭代任何集合视图时,必须手动同步返回的映射 Collection

系统中有两个线程。一个是读线程,另一个是写线程

使用以下代码同步映射

Map<String,ArrayList<String>> m = Collections.synchronizedMap(new HashMap<String,ArrayList<String>())

mapm=Collections.synchronizedMap(新的HashMap可能是这样的。这样做不安全

当用户迭代任何集合视图时,必须手动同步返回的映射

Collections.synchronized…
使单个方法调用原子化,因此不需要进一步的同步。但迭代不仅仅是单个方法调用,因此需要额外的同步。下面是一个示例

    Map<String, String> shared = Collections.synchronizedMap(new HashMap<>());

    new Thread(() -> {
        while (true) {
            synchronized (shared) {
                for (String key : shared.keySet()) {
                    System.out.println(key);
                }
            }
            try {
                Thread.sleep(1000);
            } catch (Exception e) {
                break;
            }
        }
    }).start();

    new Thread(() -> {
        while (true) {
            try {
                // this is atomic
                shared.put(UUID.randomUUID().toString(), "Yo!");
                Thread.sleep(1000);
            } catch (Exception e) {
                break;
            }
        }
    }).start();
}
Map shared=Collections.synchronizedMap(新的HashMap());
新线程(()->{
while(true){
同步(共享){
for(字符串键:shared.keySet()){
系统输出打印项次(键);
}
}
试一试{
睡眠(1000);
}捕获(例外e){
打破
}
}
}).start();
新线程(()->{
while(true){
试一试{
//这是原子的
shared.put(UUID.randomuid().toString(),“哟!”);
睡眠(1000);
}捕获(例外e){
打破
}
}
}).start();
}

是的,
迭代器
仍然可能抛出
ConcurrentModificationException
,因为它与同步无关(尽管它的名字暗示了这一点)。迭代器尝试检测结构修改(添加或删除对象)无论列表的操作是否同步,都会尽最大努力尝试。 一旦通过
List.Iterator()或List.listIterator()
获得迭代器,对列表所做的任何更改(迭代器本身所做的更改除外)都将以最大努力为基础引发CME异常。 确保不会抛出
ConcurrentModificationException
的唯一方法 要么先完成读操作,然后再完成写操作(反之亦然),要么使用
ConcurrentHashMap

Map hashmap = new HashMap<String,ArrayList<String>();
----

Map<String,ArrayList<String>> m = new ConcurrentHashMap<String,ArrayList<String>(hashmap));

Map hashmap=new HashMapSo,我想我需要对读写都使用同步,对吗?@touchtstone取决于你在写的过程中做了什么。单个方法调用否,如果多个方法需要原子是,请参阅回答中的编辑。我想我需要对读写都使用同步,对吗?只有同步不会是原子的ufficient,您需要确保迭代器的操作不会相互交错。或者,我建议您使用ConcurrentHashMap中的故障安全迭代器,但故障安全迭代器使用深度副本,这将导致脏读!!@Touchstone然后我建议您从获取它的映射值开始同步迭代操作()迭代器()使用迭代器注意问题需要澄清-问题中的代码使修改变得不可能,因为没有引用它。任何东西如何修改地图?您没有保留对它的引用。嗯,我将要设计一个系统。我正在考虑使用ReadWriteLock。这就是为什么我想探索所有可能的scenarios。您问题中的代码是100%线程安全的,因为无法修改映射-没有对映射的直接引用。@Bohemian,同步视图不是不可变的。只需调用
m.put(String,List);