Ank*_*thi 8 java collections iterator list concurrentmodification
我知道如果使用迭代器在某个线程遍历它时将更改Collection,则iterator.next()将抛出ConcurrentModificationException.
但它根据列表中的元素数量显示不同的行为.
我尝试了一个代码片段,在其中遍历for-each循环中的列表,在它之间,遍历使用列表的remove()方法从列表中删除了一个元素.
理想情况下,它应该在此条件下抛出ConcurrentModificationException而不依赖于列表中的元素数量,但是当列表中的元素数量为2时,它不是真的.
案例1: 列表中的元素数量 - 1
public static void main(String[] args)
{
List<String> list=new ArrayList<String>();
list.add("One");
for (String string : list)
{
System.out.println(string);
list.remove(string);
}
}
Run Code Online (Sandbox Code Playgroud)
输出:一
线程"main"java.util.ConcurrentModificationException中的异常
这是预期的.
案例2:列表中的元素数量 - 2
public static void main(String[] args)
{
List<String> list=new ArrayList<String>();
list.add("One");
list.add("two");
for (String string : list)
{
System.out.println(string);
list.remove(string);
}
}
Run Code Online (Sandbox Code Playgroud)
输出:一
没有例外被抛出?????????
案例3:列表中的元素数量 - 3
public static void main(String[] args)
{
List<String> list=new ArrayList<String>();
list.add("One");
list.add("Two");
list.add("Three");
for (String string : list)
{
System.out.println(string);
list.remove(string);
}
}
Run Code Online (Sandbox Code Playgroud)
输出:一
线程"main"java.util.ConcurrentModificationException中的异常
抛出异常,这是理想的行为.
但是为什么它在case-2中正常运行而不抛出任何ConcurrentModificationException.
从文档(强调我的):
这个类
iterator和listIterator方法返回的迭代器是快速失败的:如果在创建迭代器之后的任何时候对列表进行结构修改,除了通过迭代器自己remove或add方法之外,迭代器将抛出一个ConcurrentModificationException.因此,在并发修改的情况下,迭代器快速而干净地失败,而不是在未来的未确定时间冒任意,非确定性行为的风险.请注意,迭代器的故障快速行为无法得到保证,因为一般来说,在存在不同步的并发修改时,不可能做出任何硬性保证.快速失败的迭代器会
ConcurrentModificationException尽力而为.因此,编写依赖于此异常的程序以确保其正确性是错误的:迭代器的快速失败行为应该仅用于检测错误.
之前的答案显示了相关文档,解释了为什么这是适当的行为; 你不能保证会收到这个例外.
如果你真的很想知道为什么你只用两个元素就不会收到它(或者实际上,如果你删除最后一个元素,无论大小如何),你可以查看源代码ArrayList.
你的循环:
for (String string : list)
Run Code Online (Sandbox Code Playgroud)
实际上是:
for(Iterator<String> i = list.iterator(); i.hasNext(); ) {
String string = i.next();
...
}
Run Code Online (Sandbox Code Playgroud)
在Arraylist内部,有一个int size代表当前元素的数量ArrayList.当你打电话时它会递减remove().
里面Iterator有一个int cursor代表当前位置(索引)的Iterator.当你打电话时,它会增加next()
hasNext()在Iterator检查当前光标位置与大小.
在您的示例中,事件链如下所示:
cursor从...开始0,size从...开始2next()被调用,cursor递增到1.remove()被称为,size递减到1hasNext()比较cursor到size,认定它们是相同的,退货false因此,如果ArrayList在迭代它时删除任何大小的倒数第二个元素,则不会收到异常.(另外值得注意的是,您永远不会处理循环中该列表中的最后一个元素;您的示例仅One出于此原因打印).
请记住 - 这是一个实现细节,不能保证.文档告诉您,您不应该依赖抛出(或不抛出)异常.ArrayList可以以不同的方式被改写,其中上面不再适用,除了被抛出(事实上,在其他JVM可能也已经是这种情况).
| 归档时间: |
|
| 查看次数: |
292 次 |
| 最近记录: |