Abnormal behaviour of java.util.List based on number of elements in it
我知道,如果在某个线程使用迭代器遍历集合时更改该集合,则迭代器.next()将抛出ConcurrentModificationException。
但它根据列表中元素的数量显示不同的行为。
我尝试了一个代码片段,在该代码片段中,我遍历了每个循环的一个列表,并在其中遍历,使用该列表的remove()方法从列表中删除了一个元素。
理想情况下,它应该在这种情况下抛出一个ConcurrentModificationException,而不依赖于列表中的元素数,但是当列表中的元素数为2时,它不是真的。
案例1:列表-1中的元素数
1 2 3 4 5 6 7 8 9 10 11 |
Output: One
Exception in thread"main" java.util.ConcurrentModificationException
这是意料之中的。
案例2:列表2中的元素数
1 2 3 4 5 6 7 8 9 10 11 12 |
Output: One
没有引发异常?????????????
案例3:列表-3中的元素数
1 2 3 4 5 6 7 8 9 10 11 12 13 |
Output: One
Exception in thread"main" java.util.ConcurrentModificationException
再次抛出一个异常,这是理想的行为。
但是为什么它在case-2中正常运行而不抛出任何ConcurrentModificationException。
之前发布的答案向您展示了相关的文档,这些文档解释了为什么这是适当的行为;您不能保证收到该异常。
如果您真的很想知道为什么不使用两个元素来接收它(或者,如果不考虑大小而删除next-to-last元素),那么可以查看
你的循环:
1 |
实际上是:
1 2 3 4 |
在arraylist内部有一个
在
在您的示例中,事件链如下:
cursor 从0 开始,size 从2 开始。- 调用
next() ,cursor 递增到1 。 - 称为
remove() ,将size 减为1 。 hasNext() 将cursor 与size 进行比较,发现两者相同,返回false 。- 循环退出而不引发异常
因此,如果在迭代过程中删除任何大小的
不过,请记住-这是一个实现细节,不能保证。文档告诉您,您不应该依赖被抛出(或未抛出)的异常。如果上述内容不再适用并且抛出了异常(实际上,在另一个可能已经存在的JVM中),则可以用不同的方式重写
从文档(强调我的):
The iterators returned by this class's
iterator andlistIterator
methods are fail-fast: if the list is structurally modified at any
time after the iterator is created, in any way except through the
iterator's ownremove oradd methods, the iterator will throw a
ConcurrentModificationException . Thus, in the face of concurrent
modification, the iterator fails quickly and cleanly, rather than
risking arbitrary, non-deterministic behavior at an undetermined time
in the future.Note that the fail-fast behavior of an iterator cannot be guaranteed
as it is, generally speaking, impossible to make any hard guarantees
in the presence of unsynchronized concurrent modification. Fail-fast
iterators throwConcurrentModificationException on a best-effort
basis. Therefore, it would be wrong to write a program that depended
on this exception for its correctness: the fail-fast behavior of
iterators should be used only to detect bugs.
从列表中删除指定元素时,列表似乎不知道其大小已更改。
试试这个:
迭代器.remove()
Removes from the underlying collection the last element returned by
the iterator (optional operation). This method can be called only once
per call to next. The behavior of an iterator is unspecified if the
underlying collection is modified while the iteration is in progress
in any way other than by calling this method.