Http://www.cnblogs.com/skywang12345/p/3308762.html
Overview
In the front, we have learned ArrayList. Next, we take ArrayList as an example to understand the fail-fast mechanism of iterator. The content includes:
1 Fail-fast Introduction
2 Fail-fast Example
3 Fail-fast Solutions
4 Fail-fast Principle
5 How to solve Fail-fast
Reprint Please specify source: http://www.cnblogs.com/skywang12345/p/3308762.html
1 Fail-fast Introduction
The fail-fast mechanism is an error mechanism in the Java Collection (Collection). Fail-fast events can occur when multiple threads operate on the contents of the same collection.
For example, when a thread A is traversing a collection through iterator, if the contents of the collection are changed by another thread, thread a accesses the collection and throws an Concurrentmodificationexception exception, resulting in a fail-fast event.
Before detailing the principles of the fail-fast mechanism, let's first recognize fail-fast with an example.
2 Fail-fast Example
Example code: (Fastfailtest.java)
1 Import java.util.*; 2 Import java.util.concurrent.*; 3 4/* 5 * @desc the Fast-fail test program in the Java collection. 6 * 7 * conditions generated by the Fast-fail event: When multiple threads operate on collection, the contents of the collection are changed by other threads if one of the threads traverses the collection through iterator The concurrentmodificationexception exception will be thrown. 8 * Fast-fail Workaround: The Fast-fail event is not generated by util.concurrent the corresponding class under the collection package. 9 *10 * In this case, the ArrayList and Copyonwritearraylist are tested separately. ArrayList generates Fast-fail events, and Copyonwritearraylist does not produce fast-fail events. 11 * (01) When using ArrayList, the Fast-fail event is generated, and the concurrentmodificationexception exception is thrown; the definition is as follows: * private static list< string> list = new arraylist<string> (); 13 * (02) When used Copyonwritearraylist, no Fast-fail event is generated; the definition is as follows: 14 * private static list<string> List = new copyonwritearraylist<string> (); *16 * @author skywang17 */18 Publ IC class Fastfailtest {private static list<string> List = new arraylist<string> ();//private s Tatic list<string> List = new copyonwritearraylist<string> (); public static voidMain (string[] args) {23 24//Start two threads at the same time to operate the list! New Threadone (). Start (), New Threadtwo (). Start (),}28 private static void Printall () {30 System.out.println (""); String value = null;33 Iterator iter = List.iterator (); Ile (Iter.hasnext ()) {$ = (String) iter.next (); System.out.print (value+ ","); 37}38 }39 40/**41 * Add 0,1,2,3,4,5 to list, followed by printall () to traverse the entire list42 */43 private static class Thr after each addition Eadone extends Thread {$ 47 public void Run () {$ int i = 0;46 while (i<6) { List.add (string.valueof (i)); printall (); i++;50}51}52 }53 54/**55 * Add 10,11,12,13,14,15 to list, followed by Printall () to iterate through the entire list56 */57 private static class Th after each added number Readtwo extends Thread {$ public void run () {i = 10;60 while (i<16) {List.add (string.valueof (i)); printall (); 63 i++;64}65}66}67 68}
Operation result :
Run the code, throw an exception java.util.concurrentmodificationexception! That is, generate Fail-fast events!
Result Description :
(in Fastfailtest), start () and new Threadtwo () starting () started with new Threadone (). Starts () Two threads to operate the list.
Threadone thread : Adds a 0,1,2,3,4,5 to the list in turn. After each number is added, the entire list is traversed through printall ().
threadtwo thread : Adds a 10,11,12,13,14,15 to the list in turn. After each number is added, the entire list is traversed through printall ().
(02) When a thread iterates through the list, the contents of the list are changed by another thread, and the concurrentmodificationexception exception is thrown and the Fail-fast event is generated.
3 Fail-fast Solutions
Fail-fast mechanism is a kind of error detection mechanism. It can only be used to detect errors because the JDK does not guarantee that the fail-fast mechanism will happen. If you are using a collection of fail-fast mechanisms in a multithreaded environment, it is recommended to replace the class under the Java.util package with the class under the Java.util.concurrent package.
So, in this case, you just need to replace the ArrayList with the corresponding class under the Java.util.concurrent package.
That is, the code
private static list<string> List = new arraylist<string> ();
Replaced by
private static list<string> List = new copyonwritearraylist<string> ();
You can resolve this approach.
4 fail-fast Principle
The Fail-fast event is generated by throwing a concurrentmodificationexception exception to trigger.
So, how does ArrayList throw concurrentmodificationexception exceptions?
We know that Concurrentmodificationexception is the exception that is thrown when you manipulate iterator. Let's look at the source code of iterator first. The iterator of ArrayList is implemented in the parent class Abstractlist.java. The code is as follows:
1 package java.util; 2 3 Public abstract class Abstractlist<e> extends Abstractcollection<e> implements list<e> {4 5. .. 6 7//Abstractlist unique attribute 8//is used to record the number of times a list has been modified: every modification (Add/delete operations), will modcount+1 9 protected transient int modcount = 0;10 11//returns the list corresponding to the iterator. In effect, the ITR object is returned. Public iterator<e> Iterator () {return new Itr ();}15//ITR is the implementation class of the Iterator (iterator) p Rivate class Itr implements iterator<e> {$ int cursor = 0;19 int lastret = -1;21 22//Repair The record value of the change. 23//Each time you create a new ITR () object, the corresponding Modcount;24//is saved when you create the new object, and each time you iterate over the elements in the list, the Expectedmodcount and Modcount are compared. 25 If not equal, the concurrentmodificationexception exception is thrown and the Fail-fast event is generated. Expectedmodcount int = modcount;27 to public boolean hasnext () {return cursor! = size (); }31 public E Next () {33//Gets the next element, it will determine whether the "Modcount saved when new ITR object" and "current Modcount" are equal; 34 // If not equal, the concurrentmodificationexception exception is thrown and the Fail-fast event is generated. Checkforcomodification (); try {Notoginseng E next = get (cursor); Tret = cursor++;39 return next;40} catch (Indexoutofboundsexception e) {$ ch Eckforcomodification (); new Nosuchelementexception ();}44}45 LIC void Remove () {if (Lastret = =-1) +-throw new IllegalStateException (); Eckforcomodification (); try {AbstractList.this.remove (Lastret); Lastret < cursor) cursor--;55 Lastret = -1;56 Expectedmodcount = MODCOUNT;57} catch (Indexoutofboundsexception e) {$ throw new Concurrentmodificationexceptio n ();}61}60 final void Checkforcomodification () {63 if (modcount! = Expectedmodcount) + throw new concurrentmodificationexception (); 65}66 }67 68 ... 69}
From there, we can see that the checkforcomodification () is executed when you call next () and remove (). If "modcount is not equal to Expectedmodcount", the concurrentmodificationexception exception is thrown, resulting in a fail-fast event.
To understand fail-fast mechanism, we need to understand when "modcount is not equal to Expectedmodcount"!
From the ITR class, we know that Expectedmodcount is assigned a value of Modcount when creating ITR objects. Through ITR, we know: Expectedmodcount cannot be modified to be not equal to Modcount. Therefore, it is necessary to verify when Modcount will be modified.
Next, we look at the source code of ArrayList, to see how Modcount was modified.
1 package java.util; 2 3 public class Arraylist<e> extends abstractlist<e> 4 implements List<e>, Randomaccess, Clo Neable, java.io.Serializable 5 {6 7 ... 8 9//List of capacity changes, the corresponding synchronization function of the public void ensurecapacity (int mincapacity) {one modcount++; oldcapacity = Elementdata.length; if (Mincapacity > Oldcapacity) {newcapaci Object olddata[] = elementdata; Ty = (oldcapacity * 3)/2 + 1; if (Newcapacity < mincapacity) newcapacity = mincapacity; //mincapacity is usually close to size, so this is a win:19 Elementdata = arrays.copyof (eleme Ntdata, newcapacity); 20} 21} 22 23 24//Add element to queue last public boolean add (E e) {26//modify Modcount Ens Urecapacity (size + 1); Increments modcount!! elementdata[size++] = e; return true; 30} 31 32 33//add element to the specified location, public void Add (int index, E element) {if (Index > Size | | Index < 0) 36 throw new Indexoutofboundsexception (PNS "Index:" +index+ ", Size:" +size); 38 39//Modify Modcount ensurecapacity (size+1); Increments modcount!! System.arraycopy (Elementdata, index, Elementdata, index + 1, size-index); Elementdata[index] = element; size++; 45} 46 47//Add Collection AddAll public boolean (collection<? extends e> c) {object[] a = C.toar Ray (); numnew int = a.length; 51//Modify Modcount ensurecapacity (size + numnew); Increments Modcount system.arraycopy (A, 0, elementdata, size, numnew); The size + = Numnew; return numnew! = 0; 56} 57 58 59//Delete the element at the specified position E remove (int index) {rangecheck (index); 62 63 Modified Modcount modcount++; 65 E OldValue = (e) elementdata[index]; nummoved int = size-index-1; if (nummoved > 0) system.arraycopy (elementdata, index+1, Elementdata, Index, nummoved); Elementdata[--size] = null; Let GC does its work oldValue return; 73} 74 75 76//Quick Delete element at specified location fastremove private void (int index) {78 79//Modify Modcount 80 modcount++; Bayi int nummoved = size-index-1; (nummoved > 0) system.arraycopy (elementdata, index+1, Elementdata, index, 84 nummoved); Elementdata[--size] = null; Let GC do it work 86} 87 88//Empty set public void clear () {90//modify Modcount Modcoun t++; 94 (int i = 0; i < size; i++) elementdata[i] = null; the size = 0; 98} 99 100 ... 101}
From this, we find that either add (), remove (), or clear () changes the value of Modcount as long as it involves modifying the number of elements in the collection.
Next, we will systematically comb how the fail-fast is produced. The steps are as follows:
(&NBSP); creates a new ArrayList with the name ArrayList.
(&NBSP); add content to ArrayList.
Create a new thread a , and in thread a read the value of ArrayList repeatedly through iterator .
create a new thread B , and in thread B remove a Node a in ArrayList.
(05) At this point, an interesting event is generated.
At some point, thread A creates a ArrayList iterator. At this point, Node A still exists in ArrayList, and when ArrayList is created, Expectedmodcount = Modcount (assuming they have a value of n at this time).
"Thread A" was executed at some point during the traversal of ArrayList, and "thread B" removed "Node A" in ArrayList. When thread B executes remove (), "modcount++" is executed in remove (), and Modcount becomes n+1 !
Thread A is then traversed, and when it executes to the next () function, calls Checkforcomodification () to compare the sizes of "Expectedmodcount" and "Modcount", while "expectedmodcount=n "," modcount=n+1 ", then throws an concurrentmodificationexception exception, producing the Fail-fast event.
At this point, we fully understand how fail-fast is produced!
That is, when multiple threads operate on the same set, when a thread accesses the collection, the contents of the collection are changed by other threads (that is, other threads change the value of the Modcount by means of Add, remove, clear, etc.); The concurrentmodificationexception exception is thrown and the Fail-fast event is generated.
5 How to solve Fail-fast
Above, explained the "solution fail-fast mechanism", also knew "fail-fast the root cause". Next, let's talk a little further about how the Java.util.concurrent package solves the Fail-fast event.
or ArrayList corresponding to the copyonwritearraylist to explain. Let's take a look at Copyonwritearraylist's source code:
View Code
From this, we can see:
(01) and ArrayList inherit from Abstractlist, Copyonwritearraylist does not inherit from Abstractlist, it simply implements the list interface.
The iterator returned by the iterator () function of ArrayList is implemented in Abstractlist, and Copyonwritearraylist is its own implementation iterator.
When next () is called in the iterator implementation class of ArrayList, "Checkforcomodification () is called to compare the size of ' expectedmodcount ' and ' modcount '; Copyonwritearraylist iterator implementation class, there is no so-called checkforcomodification (), and will not throw a Concurrentmodificationexception exception!
Java Collection Series 04 Fail-fast summary (through ArrayList to illustrate the principle of fail-fast, solutions)