Arraylist,HashMap,HashSet等容器持有的的fail-fast迭代器,具体实现原理和modcount域有关.
Lets looks at following code
01 public class FailFastIteratorTest { 02 03 public static void main(String[] args) { 04 05 final List<String> list = new ArrayList<String>(); 06 list.add("a"); 07 list.add("b"); 08 list.add("c"); 09 10 Iterator<String> it = list.iterator(); 11 12 Thread t = new Thread() { 13 14 public void run() { 15 list.add("d"); 16 list.add("e"); 17 list.add("f"); 18 } 19 }; 20 t.start(); 21 22 // Make sure, thread gets kicked off 23 try { 24 Thread.sleep(1000); 25 } catch (InterruptedException e) { 26 } 27 28 while(it.hasNext()){ 29 System.out.println(it.next()); 30 } 31 } 32 }
What will happen when above program is run ? Hope you have guessed it right, you will get java.util.ConcurrentModificationException thrown at line it.next(). Because its not allowed for a thread to modify the collection, while another is iterating over it. Ok, lets make it single threaded and modify code (lines 06 to 30) as below:
1 list.add("a"); 2 list.add("b"); 3 list.add("c"); 4 5 Iterator<String> it = list.iterator(); 6 list.add("d"); 7 while(it.hasNext()){ 8 System.out.println(it.next()); 9 }
Huh!.. again you will get throw ConcurrentModificationException thrown at line it.next(). After the creation of Iterator, the container cannot be modified at any time by any method other than the Iterator‘s own remove or add methods. Iterators that do this are known as fail-fast iterators, as they fail quickly and cleanly, rather that risking arbitrary, non-deterministic behavior at an undetermined time in the future. Ok Now lets dig little deep and ascertain how fail-fast iterators are implemented. Java uses modCount variable to track number of modifications made. Here goes the javadoc comments for declaraion of modCount variable in AbstractList class.
01 /** 02 * The number of times this list has been structurally modified. 03 * Structural modifications are those that change the size of the 04 * list, or otherwise perturb it in such a fashion that iterations in 05 * progress may yield incorrect results. 06 * 07 * This field is used by the iterator and list iterator implementation 08 * returned by the iterator and listIterator methods. 09 * If the value of this field changes unexpectedly, the iterator (or list 10 * iterator) will throw a ConcurrentModificationException in 11 * response to the next, remove, previous, set or add operations. 12 * This provides fail-fast behavior, rather than non-deterministic behavior in 13 * the face of concurrent modification during iteration. 14 * 15 * Use of this field by subclasses is optional. If a subclass 16 * wishes to provide fail-fast iterators (and list iterators), then it 17 * merely has to increment this field in its add(int, Object) and 18 * remove(int) methods (and any other methods that it overrides 19 * that result in structural modifications to the list). A single call to 20 * add(int, Object) or remove(int) must add no more than 21 * one to this field, or the iterators (and list iterators) will throw 22 * bogus ConcurrentModificationExceptions. If an implementation 23 * does not wish to provide fail-fast iterators, this field may be 24 * ignored. 25 */ 26 protected transient int modCount = 0; 27 28 Now lets look at implementation iterator class returned by list. 29 30 private class Itr implements Iterator<E> { 31 int expectedModCount = modCount; 32 33 public boolean hasNext() { 34 // implementation omitted 35 } 36 37 public E next() { 38 checkForComodification(); 39 // implementation omitted 40 41 } 42 43 private void checkForComodification() { 44 if (modCount != expectedModCount) 45 throw new ConcurrentModificationException(); 46 } 47 }
As it is clear, expectedModCount is initialized to modCount at creation of Iterator and any method that modify the list would increament modCount. Every call to next() method, checks expectedModCount and throws ConcurrentModificationException if it does not match with modCount.
原文:http://www.cnblogs.com/Guoyutian/p/5185456.html