Chapter 3 CopyOnWriteArrayList source code parsing: copyonwritearraylist

Source: Internet
Author: User

Chapter 3 CopyOnWriteArrayList source code parsing: copyonwritearraylist

Note: Before reading this article, if you are not clear about the underlying layer of ArrayList, we recommend that you check it first.ArrayListSource code parsing.

Http://www.cnblogs.com/java-zhao/p/5102342.html

1. Master the following points for CopyOnWriteArrayList:

  • Create: CopyOnWriteArrayList ()
  • Add element: add (E) Method
  • Get a single object: get (int) Method
  • Delete object: remove (E) Method
  • Traverse all objects: iterator (). In practice, an enhanced for loop is more commonly used for traversal.

Note: CopyOnWriteArrayList is a thread-safe, unlocked ArrayList during read operations.

 

2. Create

Public CopyOnWriteArrayList ()

Usage:

List<String> list = new CopyOnWriteArrayList<String>();

Source code:

Private volatile transient Object [] array; // underlying data structure/*** get array */final Object [] getArray () {return array ;} /*** set Object [] */final void setArray (Object [] a) {array = a;}/*** create a CopyOnWriteArrayList * Note: creates an array of 0 elements */public CopyOnWriteArrayList () {setArray (new Object [0]);}View Code

Note:

  • Set an Object [] with a capacity of 0; ArrayList will create an Object with a capacity of 10 []

 

3. Add Elements

Public boolean add (E e)

Usage:

list.add("hello");

Source code:

/*** Add an element at the end of the array * 1) Get the lock * 2) Lock * 3) Get the old array and its length * 4) create a new array, capacity is the length of the old array + 1, copy the old array to the new array * 5) Add the elements to be added to the end of the new array, set global array to the new array */public boolean add (E e) {final ReentrantLock lock = this. lock; // Why not use this directly here. lock (that is, the initialized lock in the class) to lock the lock. lock (); // lock try {Object [] elements = getArray (); // obtain the current array int len = elements. length; // get the current array element/** Arrays. the general execution process of copyOf (elements, len + 1): * 1) create a new array with the capacity of len + 1, * 2) copy the old array elements to the new array, * 3) returns the new array */Object [] newElements = Arrays. copyOf (elements, len + 1); newElements [len] = e; // set the end element of the new array to e setArray (newElements ); // set global array to return true;} finally {lock. unlock (); // unlock }}View Code

Note:

  • Arrays. copyOf (T [] original, int newLength) This method has been explained in ArrayList

Question:

  • In the add (E) method, why do we need to redefine a ReentrantLock instead of directly using that defined class variable lock (Global lock)
    • A: Actually, it is written like this. Even if multiple references exist in add, remove, and set, this is the last instance. lock, so no matter how you define a ReentrantLock in add, remove, and set, the last lock used in add, remove, and set is this. lock, that is, at the same time, only one of add/remove/set is running. In this case, the following code can be modified. Code before modification: public boolean add (E e) {final ReentrantLock lock = this. lock; // Why not use this directly here. lock (that is, the initialized lock in the class) to lock the lock. lock (); // lockView Code

      Modified code:

      Public boolean add (E e) {// final ReentrantLock lock = this. lock; // Why not use this directly here. lock (the lock already initialized in the class) to lock this. lock. lock (); // lockView Code
  • According to the code above, we can see that each time we add a new element, we need to perform an array replication consumption. Why don't we set the array element to a large one at a time (for example, like the ArrayList, set to 1.5 times + 1), which will greatly reduce the consumption caused by array element replication?

 

4. Obtain Elements

Public E get (int index)

Usage:

List. get (0)

Source code:

/*** Retrieve element by subscript * 1) retrieve array * 2) retrieve element by index */public E get (int index) {return (E) (getArray () [index]);}View Code

Note:

  • No locks are required for obtaining

Q: In the book distributed Java application: basics and practices, the author points out that read operations may cause dirty reads. Why?

From the class attribute section, we can see that the array is modified by volatile, that is, after you write volatile, the written array will be forcibly refreshed to the main memory, during the reading operation, when you read the array (getArray (), it will force the array to be read to the working memory from the primary memory, so it should not be dirty read !!!

 

5. Delete Elements

Public boolean remove (Object o)

Usage:

list.remove("hello")

Source code:

/*** Delete the first o in the list * 1) Get the lock and lock * 2) Get the length of the old array and the old array len * 3) if the length of the old array is 0, returns false * 4) if the old array has a value, create a new array with a capacity of len-1 * 5) traverse from 0 all elements except the last element in the array * 5.1) copy the elements in the old array before the deleted elements to the new array, * 5.2) copy the elements in the old array after the deleted elements to the new array * 5.3) assign the new array to Global array * 6) if the last element of the old array is to be deleted, * 6.1) copy the elements before the elements in the old array to the new array * 6.2) and assign the new array to the Global array */public boolean remove (Object o) {final ReentrantLock lock = this. lock; lock. lock (); try {Object [] elements = getArr Ay (); // obtain the original array int len = elements. length; // obtain the original array length if (len! = 0) {// If data exists // Copy while searching for element to remove // This wins in the normal case of element being present int newlen = len-1; // The length of the new array is the length of the original array-1 Object [] newElements = new Object [newlen]; // create a new array for (int I = 0; I <newlen; ++ I) {// traverse the new array (excluding the last element) if (eq (o, elements [I]) {// copy the elements deleted from the old array to the new array for (int k = I + 1; k <len ;++ k) newElements [k-1] = elements [k]; setArray (newElements); // assign the new array to the Global array return true ;} else newElements [I] = elements [I]; // copy the elements before the elements are deleted from the old array to the new array} if (eq (o, elements [newlen]) {// setArray (newElements); return true;} return false;} finally {lock. unlock ();}}View Code

Determine whether two objects are equal:

/*** Determine whether o1 and o2 are equal */private static boolean eq (Object o1, Object o2) {return (o1 = null? O2 = null: o1.equals (o2 ));}View Code

Note:

  • Lock required
  • The removal of ArrayList uses System. arraycopy (this is an native method), but it is not used here. Therefore, theoretically, the removal performance is lower than that of ArrayList.

 

6. traverse all elements

Iterator () hasNext () next ()

Usage:

Explained in:

Iterator <String> itr = list. iterator (); while (itr. hasNext () {System. out. println (itr. next ());}View Code

Actually used:

For (String str: list) {System. out. println (str );}View Code

Source code:

Public Iterator <E> iterator () {return new COWIterator <E> (getArray (), 0 );}View Code private static class COWIterator <E> implements ListIterator <E> {private final Object [] snapshot; // array snapshot private int cursor; // It can be seen as an array index private COWIterator (Object [] elements, int initialCursor) {cursor = initialCursor; snapshot = elements; // assign the actual array to the array snapshot} public boolean hasNext () {return cursor <snapshot. length; // 0 ~ Snapshot. length-1} public E next () {if (! HasNext () throw new NoSuchElementException (); return (E) snapshot [cursor ++];}View Code

Note: This piece of code is very simple. Just look at the code comments.

Note:

Since only one copy of the global array is traversed, even if the global array is added, deleted, and changed, the copy will not change, so no concurrency exception will occur. However, some objects that have just been deleted may be read during traversal.

Note:

 

Summary:

  • Thread security: The ArrayList is unlocked during read operations.
  • The underlying data structure is an Object [] with an initial capacity of 0. Each time an element is added, the size is + 1, and the array is copied once.
  • Add, delete, modify, and lock; read locks
  • During the traversal process, only one copy of the global array is traversed. Even if the global array is added, deleted, and changed, the copy will not change, so no concurrency exception will occur.
  • Select CopyOnWriteArrayList

Question:

  • Each time a new element is added, an array is copied and consumed. Why not set the array element to a greater value (for example, set it to 1.5 times + 1 as in ArrayList ), this will greatly reduce the consumption caused by copying array elements?
  • The get (int) operation will cause dirty reads. Why?

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.