Dau*_*aud 1 java concurrency loops map
假设一个映射包含整数键,并且一个字符串列表作为其值.然后,我不能这样做:
for (Map.Entry<Integer, List<String>> entry : map.entrySet()){
for (String string : entry.getValue()){
if (string.startsWith("a")){
entry.getValue().remove(string);
}
}
}
Run Code Online (Sandbox Code Playgroud)
它抛出ConcurrentModificationException.但如果我做以下事情:
for (Map.Entry<Integer, List<String>> entry : map.entrySet()){
entry.setValue(new ArrayList<String>());
}
Run Code Online (Sandbox Code Playgroud)
这非常有效.我们现在不是在修改底层地图吗?
问题与Map您使用值列表的方式无关.以下将失败ArrayList:
for (String string : list){
if (string.startsWith("a")){
list.remove(string);
}
}
Run Code Online (Sandbox Code Playgroud)
其原因在Javadoc中讨论ArrayList:
此类的iterator和listIterator方法返回的迭代器是快速失败的:如果在创建迭代器之后的任何时候对列表进行结构修改,除了通过迭代器自己的remove或add方法之外,迭代器将抛出ConcurrentModificationException.因此,在并发修改的情况下,迭代器快速而干净地失败,而不是在未来的未确定时间冒任意,非确定性行为的风险.
(换一种方式:如果你从列表中删除元素,可能不是指向底层数组中的右手食指再迭代因此,而不是让你使用可能损坏的迭代器,它抛出一个ConcurrentModificationException出于礼貌让你知道你需要重新设计你的程序.)
一个简单的解决方法是使用
Iterator<String> itr = entry.getValue().iterator();
while (itr.hasNext()) {
if (itr.next().startsWith("a")) {
itr.remove();
}
}
Run Code Online (Sandbox Code Playgroud)