CopyOnWriteArrayList is introduced
CopyOnWriteArrayList is a thread-safe ArrayList whose changes are made on an underlying copied array (snapshot), mimicking the copy-on-write strategy
Source code analysis
Initialization: An Object array of size 0 is created internally as the initial value of the array
== takes the constructor ==
Add elements
- The thread calling the Add method first executes code to acquire the exclusive lock, if multiple threads call it
add
Method only one thread acquires the lock, and the other threads are blocked until the lock is released. - So when a thread acquires the lock, it guarantees that no other thread will modify the array while the thread is adding elements.
- The thread acquires the lock and executes code to acquire the array, and then executes code to copy the array to a new array
CopyOnWriteArrayList
Is an unbounded list) and adds the new element to the new array. - The code is then executed to replace the old array with the new one and release the lock before returning. Because of the lock, so the whole
add
Process is aatomic
Operation. One thing to note - When you add an element, you first copy one
The snapshot
And then inAdd a snapshot to a snapshot
.Instead of just doing it on the original array
.
E set(int index,E element)
public E set(int index, E element) { final ReentrantLock lock = l.lock; lock.lock(); try { rangeCheck(index); checkForComodification(); E x = l.set(index+offset, element); expectedArray = l.getArray(); return x; } finally { lock.unlock(); }}Copy the code
- The exclusive lock was acquired first, preventing other thread pairs
array
Array is modified, then the current array is retrieved, and the get method is called to get the element at the specified location - If the value of the element at the specified location does not match the new value, a new array is created and the element is copied, then the new array is modified on the specified location and the new array is set to
array
. - If the value of the element at the specified location is the same as the new value, to ensure that
volatile
Semantics, again, need to be resetarray
Although,array
The content has not changed.
Remove elements
- The exclusive lock is first acquired to ensure that the array cannot be modified by other threads while the data is being deleted, and then the elements of the array to be deleted are acquired
- It copies the remaining elements into the new array, replaces the original array with the new array, and releases the lock before returning.
Weakly consistent iterators
public static void main(String[] args) { CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>(); list.add("hello"); list.add("alibaba"); Iterator<String> itr = list.iterator(); while(itr.hasNext()){ System.out.println(itr.next()); }}Copy the code
- iterator
hasNext
The next method is used to determine if there are any more elements in the list, and the next method returns an element specifically.
public Iterator<E> iterator() { return new COWIterator<E>(getArray(), 0); } static final class COWIterator<E> implements ListIterator<E> {// Array private final Object[] snapshot; Private int cursor; // Constructor private COWIterator(Object[] elements, int initialCursor) {cursor = initialCursor; snapshot = elements; Public Boolean hasNext() {return cursor < snapshot.length; } @suppressWarnings ("unchecked") public E next() {if (! hasNext()) throw new NoSuchElementException(); return (E) snapshot[cursor++]; } · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·}}Copy the code
- If the list is not added or deleted by other threads while the thread traverses the elements using the returned iterator, the Snapshot itself is an array of the list
- Because they areReference relationship. If the list is added, deleted, or changed by another thread during the traversal, then the snapshot is a snapshot
snapshot
References. This also indicates that after getting the iterator - When this iterator element is used, other threads’ additions, deletions and changes to the list are invisible because they operate on two different arrays, which is weak consistency.
The output
hello
GG/MM
Welcome
to
xiaoff zone
Copy the code
- The main function is initialized first
arrayList
And then gets it before starting the threadarrayList
Iterators. - The child thread threadOne was first modified when it started
arrayList
The value of the first element of thearrayList
The subscript for2
and3
The element. - The main thread uses the iterator to iterate over a set of elements after the child thread completes execution. From the output, we know that none of the operations performed in the child thread are effective, which is a reflection of the weak consistency of the iterator.
- It is important to note that the operation to get the iterator must occur before the child thread operation.