我有以下代码
public static void main(String[] args) {
List<String> list = new ArrayList<>();
Arrays.stream("hello how are you".split(" ")).forEach(s -> list.add(s));
Iterator<String> it = list.iterator();
ListIterator<String> lit = list.listIterator();
while (it.hasNext()) {
String s = it.next();
if (s.startsWith("a")) {
it.remove();
} else {
System.out.println(s);
}
}
System.out.println(list);
// {here}
while (lit.hasNext()) {
String s = lit.next();
if (s.startsWith("a")) {
lit.set("1111" + s);
} else {
System.out.println(s);
}
}
System.out.println(list);
}
在这里,在遍历Iterator
之后,我尝试迭代ListIterator
。但代码会抛出ConcurrentModificationException
。我只在ListIterator
完成后才使用Iterator
进行修改,但为什么会出现此异常。
当我在{here}
而不是顶部初始化ListIterator时,代码运行完美。
ConcurrentModificationException
? Iterator
已经被另一个Iterator
初始化之后初始化它?答案 0 :(得分:2)
当两个线程同时修改列表时,是否抛出了ConcurrentModificationException?
不一定。 ConcurrentModificationException
表示在创建Iterator
后,列表已在结构上发生了变化(remove
自己的Iterator
方法除外)。这可能是由于多个线程使用相同的列表,或者可能是由于尝试在不使用ArrayList
的情况下从每个循环中的Iterator
内删除项目。
初始化迭代器,在列表上创建一个锁吗?
不,没有锁。创建Iterator
时,它会记录modCount
的{{1}}(列表状态的粗略表示,在每次结构更改时递增)。如果迭代器检测到对ArrayList
的modcount的更改,该modcount不是由自己的方法引起的,则抛出异常。
您正在从第二个迭代器获取异常,因为在实例化和使用的第二个迭代器之间对列表进行了结构更改。
为什么Java允许我们在迭代器已经被另一个迭代器初始化后初始化它?
List
不会跟踪它创建的所有迭代器或它们的状态。这样做会使实施大大复杂化。 ArrayList
方法并不完美,有点粗糙,但它很简单并且识别出许多真正的错误。
答案 1 :(得分:1)
使用第一个迭代器后,必须加载第二个迭代器。否则第二个迭代器“认为”列表没有被改变,但实际上它确实如此。因为列表被更改了,所以第二个迭代器的反应就像“等一下,不应该在这里/已经消失”并抛出一个ConcurrentModificationException
。
它允许您随时初始化迭代器。如果你不改变内容,你可能会很好,并且没有得到ConcurrentModificationException
,因为没有任何改变。
答案 2 :(得分:1)
每当您尝试使用无效迭代器时,都可能抛出ConcurrentModificationException
- 无论何时创建迭代器,然后从不同的访问点修改基础集合,都会发生这种情况。在这里,初始化lit
,然后通过it
修改列表,使其无效,这解释了异常。
答案 3 :(得分:0)
ListIterator抛出ConcurrentModificationException,它在创建后在列表中有一个修改。在您的代码中,您同时创建了Iterator和ListIterator,稍后您将从列表中删除导致ConcurrentModificationException的内容。
要避免这种情况,请将代码更改为低于1。您只需要在迭代器操作后移动ListIterator初始化。
try (PreparedStatement ps = conn.prepareStatement("insert into a(b, c) values (?, ?)") ) {
while(var4.next()) {
ps.setInt(1, rs.getInt("b"));
ps.setInt(2, rs.getInt("c"));
ps.executeUpdate();
}
} catch( SQLException e){
...
}