Why no ConcurrentModificationException in this situation with LinkedList iterator? [duplicate]

耗尽温柔 提交于 2020-01-11 05:37:10

问题


Consider the following code snippet:

List<String> list = new LinkedList<>();
list.add("Hello");
list.add("My");
list.add("Son");

for (String s: list){
    if (s.equals("My")) list.remove(s);
    System.out.printf("s=%s, list=%s\n",s,list.toString());
}

This results in output:

s=Hello, list=[Hello, My, Son]
s=My, list=[Hello, Son]

So clearly the loop was only entered twice, and the third element, "Son", never gets visited. From the underlying library code, it looks like what happens is that the hasNext() method in the iterator doesn't check for concurrent modification, only the size against the next index. Since the size has been reduced by 1 by the remove() call, the loop simply doesn't get entered again, but no ConcurrentModificationException is thrown.

This seems to contradict the contract of the iterator:

The list-iterator is fail-fast: if the list is structurally modified at any time after the Iterator is created, in any way except through the list-iterator's own remove or add methods, the list-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.

Is this a bug? Again, the contract of the iterator definitely appears to be disobeyed here - the structure of the list is structurally modified by something other than the iterator in the middle of iteration.


回答1:


Read the class-level Javadoc:

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 throw ConcurrentModificationException 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.




回答2:


From https://docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html:

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 throw ConcurrentModificationException 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.

That is, the iterator will try its best to throw exception, but isn't guaranteed to do so in all cases.

Here are some more links on how fail fast iterators works and how the are implemented - in case someone will be interested:

http://www.certpal.com/blogs/2009/09/iterators-fail-fast-vs-fail-safe/

http://javahungry.blogspot.com/2014/04/fail-fast-iterator-vs-fail-safe-iterator-difference-with-example-in-java.html

http://www.javaperformancetuning.com/articles/fastfail2.shtml

And here is another SO question where people trying to find out the same thing:

Why isn't this code causing a ConcurrentModificationException?



来源:https://stackoverflow.com/questions/27195826/why-no-concurrentmodificationexception-in-this-situation-with-linkedlist-iterato

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!