Java 当一个线程迭代(使用迭代器)而另一个线程修改非线程安全ArrayList的同一副本时,为什么没有ConcurrentModificationException
一些背景:Java 当一个线程迭代(使用迭代器)而另一个线程修改非线程安全ArrayList的同一副本时,为什么没有ConcurrentModificationException,java,multithreading,iterator,concurrentmodification,Java,Multithreading,Iterator,Concurrentmodification,一些背景: 当使用Iterator对集合进行迭代时,可能会出现java.util.ConcurrentModificationException,因为在创建Iterator对象时,会捕获集合或数组列表的修改计数(modCount),并在每次迭代时使用Iterator.next()检查modCount是否已更改,如果已更改,则抛出java.util.ConcurrentModificationException 在创建迭代器对象时(从ArrayList的iterator实现): int expec
当使用
Iterator
对集合进行迭代时,可能会出现java.util.ConcurrentModificationException
,因为在创建Iterator
对象时,会捕获集合或数组列表的修改计数(modCount
),并在每次迭代时使用Iterator.next()
检查modCount
是否已更改,如果已更改,则抛出java.util.ConcurrentModificationException
在创建迭代器对象时(从ArrayList
的iterator
实现):int expectedModCount=modCount代码>
调用下面的方法Iterator.next()
,该方法引发异常(来自ArrayList
的Iterator
实现):
我可以使用以下代码很好地复制它:
List<String> stringList = new ArrayList<String>();
stringList.add("a");
stringList.add("b");
stringList.add("c");
Iterator<String> iterator = stringList.iterator();
System.out.println("Got iterator object");
while (iterator.hasNext()) {
String player = iterator.next();
player.toString();
System.out.println("UpperCase: " + player.toUpperCase());
iterator.remove();
stringList.add("a1"); //This is root cause of exception.
}
在另一个线程中获得迭代器并开始迭代后,如何保证调用一个线程中的添加
和删除
?提示:竞争条件。Thread.start()
需要很长且不可预测的时间(相对而言,从计算角度来说)。在您更改列表之前,您没有任何代码可以保证迭代开始。@SotiriosDelimanolis谢谢。我知道了,我不知怎么错过了。我的错。我在while循环中休眠了第二个线程1秒,第一个线程也休眠了1秒,这样就没有了不必要的争用条件,我得到了异常。我将删除这个问题。@aff我实际上在while循环的第一个线程中有睡眠,但我没有发布它。我错过了第二个线程。索蒂里奥斯睁开了我的眼睛,我明白了。谢谢你的留言。我将删除这个问题。请注意,即使使用了正确的交错,因为modCound不是易失性的,所以您没有可见性保证,并且第一个线程可能看不到第二个线程所做的修改。此行为试图帮助您检测错误,但不能提供任何保证。如何保证在另一个线程中获取迭代器并开始迭代后,调用一个线程中的添加
和删除
?提示:竞争条件。Thread.start()
需要很长且不可预测的时间(相对而言,从计算角度来说)。在您更改列表之前,您没有任何代码可以保证迭代开始。@SotiriosDelimanolis谢谢。我知道了,我不知怎么错过了。我的错。我在while循环中休眠了第二个线程1秒,第一个线程也休眠了1秒,这样就没有了不必要的争用条件,我得到了异常。我将删除这个问题。@aff我实际上在while循环的第一个线程中有睡眠,但我没有发布它。我错过了第二个线程。索蒂里奥斯睁开了我的眼睛,我明白了。谢谢你的留言。我将删除这个问题。请注意,即使使用了正确的交错,因为modCound不是易失性的,所以您没有可见性保证,并且第一个线程可能看不到第二个线程所做的修改。此行为试图帮助您检测bug,但不能提供任何保证。
List<String> stringList = new ArrayList<String>();
stringList.add("a");
stringList.add("b");
stringList.add("c");
Iterator<String> iterator = stringList.iterator();
System.out.println("Got iterator object");
while (iterator.hasNext()) {
String player = iterator.next();
player.toString();
System.out.println("UpperCase: " + player.toUpperCase());
iterator.remove();
stringList.add("a1"); //This is root cause of exception.
}
private static void iteratorException() {
final List<String> stringList = new ArrayList<String>();
Thread thread = new Thread(){
@Override
public void run() {
System.out.println("T1");
stringList.add("a");
stringList.add("b");
stringList.add("c");
Iterator<String> iterator = stringList.iterator();
System.out.println("Got iterator object");
while (iterator.hasNext()) {
String player = iterator.next();
player.toString();
System.out.println("UpperCase: " + player.toUpperCase());
iterator.remove();
//stringList.add("a1");
}
}
};
Thread thread2 = new Thread(){
@Override
public void run() {
System.out.println("T2");
stringList.add("d");
stringList.remove("a");
System.out.println("finished T2");
}
};
thread.start();
thread2.start();
}