Brief introduction
Copyonwritearraylist is a non-blocking, thread-safe list implementation provided in the JDK concurrent package. Copyonwritearraylist is a thread-safe, and ArrayList that is unlocked during read operations. Copyonwritearraylist data modifications, the data will be locked, each modification, the first copy of the entire array, and then modify some of these elements, complete the above operation, with an atomic operation to replace the entire array of pointers.
When the copyonwritearraylist is read, the data is not locked, the data that needs to be queried is returned directly, and if the entire array is returned, the entire array is copied and returned to ensure that the internal array is read-only in any case.
Introduction to "Copyonwrite"
You've heard this concept when you're learning about Linux OS processes/threads, the direct translation is called "Write-time copy", saying that when a new thread needs to be created to make a fork () call, there is no real sense of opening a new thread memory resource, only when the thread has "write" Copies the data of the parent thread as the initial content of the new thread.
In the JavaSE5 concurrency package, the implementation of Copyonwritearraylist also utilizes a similar approach. When the contents of the array change, copy a new one out, and the object reference assigned to the list of properties, the old array access is still valid, not subject to new operational interference.
Copyonwritearraylist fit for what scene.
There are a number of changes to the container object, and for each change in the copyonwritearraylist, copyonwritearraylist copies a copy of the data, which is obviously a cost. So, copyonwritearraylist is actually more suitable for read operations than for write-operations scenarios .
copyonwritearraylist
public class copyonwritearraylist<e> implements List<e>, Randomaccess, Cloneable, java.io.Serializable
But even with copyonwrite, when you create a new array object and assign it to a value when you write, you are still affected by multithreading, which is protected by a lock.
Transientfinal Reentrantlock lock =new reentrantlock ();
This is the lock property in the Copyonwritearraylist class. Copyonwritearraylist, which contains an array object that can only be accessed by GetArray () and SetArray () two methods, the source code is as follows:
/** the array, accessed only via Getarray/setarray. */
Private volatile transient object[] array;
/**
* Gets the array. Non-private so-also be accessible
* FROM Copyonwritearrayset class.
*/
Final object[] GetArray () {
return array;
}
/**
* Sets the array.
*/
final void SetArray (object[] a) {
Array = A;
}
Copyonwritearraylist Constructors Copyonwritearraylist provides three constructors, Copyonwritearraylist (): Constructs an object with an empty content copyonwritearraylist (collection<? extends E> c): Constructs a new object Copyonwritearraylist (e[] Tocopyin according to the contents of the incoming parameter: according to the contents of the incoming array, construct a new object the source code for the above three methods is as follows:
1 public copyonwritearraylist () {
SetArray (new object[0]);
}
Create an array of size 0
2 public copyonwritearraylist (collection<? extends e> c) {
object[] elements = C.toarray ();
C.toarray might (incorrectly) not return object[] (6260652)
if (Elements.getclass ()!= object[].class)
elements = arrays.copyof (elements, Elements.length, object[].class);
SetArray (elements);
}
Converts the incoming container to an array, and if the incoming element cannot directly convert the array type, create one and then copy to the new array, then set to the array property through an atomic operation.
Constructs an object[] object of the same length based on the length of the incoming parameter C, and fills the contents of C into this object[object in sequence
(1). The constructor here, which does not explicitly determine whether C is null, actually throws a null pointer exception if C is null
(2). Here for the content in C copy, is a shallow copy rather than a deep copy
Deep copy (deep copy) and shallow copy (shallow copy) concept explanation:
Deep copy (deep copy) and shallow copy (shallow copy) are two more common concepts, especially in the C + + language, if not understood, it will be in the delete when the problem, but we are fortunate to use Java. Although Java automatically manages the collection of objects, we should pay enough attention to deep copy (deep copy) and shallow copy (shallow copy), because sometimes these two concepts often bring us no small confusion.
A shallow copy is a copy of an object that simply copies the object itself (including the basic variables in the object), not the object that the object contains. A deep copy not only copies the object itself, but also copies all objects that the reference to the object contains. For example, it is clearer that the object A1 contains references to B1, B1 contains references to C1. The shallow copy A1 gets a2,a2 still contains references to B1, and B1 still contains references to C1. Deep copy is recursive for shallow copy, deep copy A1 get a2,a2 contains references to B2 (B1 copy), B2 contains references to C2 (C1 copy). If you do not overwrite the Clone () method, the object that is called by this method is a shallow copy
3 public copyonwritearraylist (e[] tocopyin) {
SetArray (arrays.copyof (Tocopyin, Tocopyin.length, Object[].class));
}
Based on the length of the incoming parameter, an array object of the same length and content is constructed, encapsulated in the Copyonwritearraylist
Copyonwritearraylist Read Operation
Read related operations
For read operations, there is no need to lock, directly read the reference to the corresponding object. The old array object is always available, because even if the array changes, it also opens up new arrays and modifies them in the new array.
Public E get (int index): fetch the corresponding element according to the index, read does not need to lock
The public iterator<e> iterator () invokes the iterator method, creates a new instance of the Cowiterator object, saves a snapshot of the current array, and only iterates through the snapshot array when the next traversal is called. Therefore, Concurrentmodificatiedexception is not thrown when traversing copyonwritearraylist.
Public listiterator<e> Listiterator ()
Public listiterator<e> listiterator (final int index)
1 Get operation
Public E get (int index) {
Return (E) (GetArray () [index]);
}
The operation is simple, directly to get the current array of elements corresponding to the position, this method is not lock-protected, so may appear to read dirty data phenomenon. But in contrast, performance can be very high, copyonwritearraylist is a good choice for scenarios where less reading and dirty data will not affect a lot.
2 iterator ()
Public iterator<e> iterator () {
return new Cowiterator<e> (GetArray (), 0);
}
A new Cowiterator object instance is created after the iterator method is called, and a snapshot of the current array is saved, and only the snapshot array is traversed when the next traversal is called. Therefore, Concurrentmodificatiedexception is not thrown when traversing copyonwritearraylist.
Use of iterator iterator. Copyonwritearraylist internally gives the implementation of the Cowiterator class, also very simple, only the array snapshot properties and index cursor properties. Snapshot's name is very well defined, meaning "snapshot". In fact, the Copyonwritearraylist iterator object is the snapshot at the time of the build, and the subsequent iterative reads are based on this snapshot.
Cowiterator meaning Copyonwriteiterator
private static class Cowiterator<e> implements Listiterator<e> {
/** Snapshot of the array **/
Private final object[] snapshot;
/** Index of element to is returned by subsequent call to next. */
private int cursor;
Private Cowiterator (object[] elements, int initialcursor) {
cursor = Initialcursor;
snapshot = elements;
}
public Boolean hasnext () {
return cursor < snapshot.length;
}
public Boolean hasprevious () {
return cursor > 0;
}
Public E Next () {
if (! Hasnext ())
throw new Nosuchelementexception ();
Return (E) snapshot[cursor++];
}
Public E Previous () {
if (! hasprevious ())
throw new Nosuchelementexception ();
Return (E) snapshot[--cursor];
}
public int Nextindex () {
return cursor;
}
public int Previousindex () {
return cursor-1;
}
/**
* Not supported. Always throws Unsupportedoperationexception.
* @throws unsupportedoperationexception always; <tt>remove</tt>
* is isn't supported by this iterator.
*/
public void Remove () {
throw new Unsupportedoperationexception ();
}
/**
* Not supported. Always throws Unsupportedoperationexception.
* @throws unsupportedoperationexception always; <tt>set</tt>
* is isn't supported by this iterator.
*/
public void Set (E e) {
throw new Unsupportedoperationexception ();
}
/**
* Not supported. Always throws Unsupportedoperationexception.
* @throws unsupportedoperationexception always; <tt>add</tt>
* is isn't supported by this iterator.
*/
public void Add (e e) {
throw new Unsupportedoperationexception ();
}
}
Copyonwritearraylist Write OperationThe lock object property of the Reentrantlock class is in the Copyonwritearraylist. When modifying an object of the Copyonwritearraylist class, it is necessary to consider multiple threads accessing the array object. The use of locks, then, is necessary.
In Copyonwritearraylist, the process of copyonwrite is usually done in this way. First copy a new array on the basis of the properties of the original array object, and the other changes are done on the new array object, and when all the modifications are complete, the reference to the new array object is given to the array Property object of the Copyonwritearraylist class. The whole process is carried out under the protection of the lock.
1 new
Public boolean Add (e) lock operation to write element E to the tail of the list
public void Add (int index, E Element) inserts an element into the index position
public boolean addall (int index, COLLECTION<? extends e> c) Inserts the collection C to the indexed index position
public boolean addall (collection<? extends e> c) Inserts collection C into the tail of the list
public boolean addifabsent (e e) Inserts an element into the list if element E is not in the list
public int addallabsent (COLLECTION<? extends e> c) If set C is not in the list, insert the collection C into the list
2 modification
Public E Set (int index, E Element) replaces elements of index positions with element elements
3 Delete
Public E-Remove (int index) deletes the element of the index position
public boolean remove (Object o) Delete element o
public boolean RemoveAll (collection<?> c) Delete collection C
1.1 Add (E E)
Public boolean Add (E e) {
Final Reentrantlock lock = This.lock;
Lock.lock ();
try {
object[] elements = GetArray ();
int len = elements.length;
object[] newelements = arrays.copyof (elements, Len + 1);
Newelements[len] = e;
SetArray (newelements);
return true;
finally {
Lock.unlock ();
}
}
Analysis: The Add method does not add keyword synchronized, but is reentrantlock to ensure thread safety, and the difference here and ArrayList is that each time a new object array is created, which is the size of the current array plus 1, Copies the contents of the previous array into the new array, puts the newly added object at the end of the array, and finally makes a reference switch to assign the newly created array object to the global array object.
public boolean remove (Object o) {
Final Reentrantlock lock = This.lock;
Lock.lock ();
try {
object[] elements = GetArray ();
int len = elements.length;
if (len!= 0) {
Copy while searching for element to remove
This wins in the normal case of element being present
int newlen = len-1;
object[] newelements = new Object[newlen];
for (int i = 0; i < Newlen; ++i) {
if (eq (o, elements[i])) {
Found one; Copy remaining and exit
for (int k = i + 1; k < Len; ++k)
NEWELEMENTS[K-1] = elements[k];
SetArray (newelements);
return true;
} else
Newelements[i] = elements[i];
}
Special handling for the last cell
if (eq (o, Elements[newlen])) {
SetArray (newelements);
return true;
}
}
return false;
finally {
Lock.unlock ();
}
}
Analysis: This method is also through Reentrantlock to ensure thread safety, first create an array that is 1 smaller than the current array, and iterate through the array, such as finding equals or null elements, assigning all the subsequent elements to the new array, and doing a reference switch, returning true, if not found, The current element is assigned to the new array object. Finally, the last element in the array, such as the last element that is equal to the element to be deleted, assigns the current array object to the newly created array object, completes the delete action, and returns False if the last element is not equal to the element to be deleted. This method copy process does not invoke system arraycopy to complete,
copyonwritearraylist Other Actionspublic Boolean IsEmpty ()
Public Boolean contains (Object o)
public boolean Containsall (collection<?> c)
public int size ()
public boolean equals (Object O)
public void Clear () clears the array
Copyonwritearrayset IntroductionIn the Java.util.concurrent package, in addition to the Copyonwritearraylist class, there is also such a class copyonwritearrayset. The implementation of the Copyonwritearrayset is entirely based on copyonwritearraylist.
public class Copyonwritearrayset<e> extends abstractset<e> implements Java.io.Serializable
Constructor: Private final copyonwritearraylist<e> al;
/**
* Creates an empty set.
*/
Public Copyonwritearrayset () {
Al = new copyonwritearraylist<e> ();
}
You can see that Copyonwritearrayset is based on the copyonwritearraylist implementation, and the only difference is that the Copyonwritearraylist Addifabsent method is invoked at Add. The Addifabsent method also uses lock protection and is in a new size +1 object array. Traverses the current object[] array, such as the current element in the object[] array, returns directly, if not the tail of the object[array, and returns. From the analysis you can see that copyonwritearrayset in the add, each time the array traversal, so its performance will be slightly lower than copyonwritearraylist.
For more details, please refer to the JDK, please add.
ReferenceJDK1.6 Copyonwritearraylist Source