This article is reproduced in Li Xiaomu
Thread safe collection class CopyOnWriteArrayList
For the ArrayList set, there is no security control on concurrency. The implementation of Vector on concurrency security uses the synchronized keyword. If the two sets are modified in the enhanced for loop, an exception of ConcurrentModificationException will be reported.
Every operation on the set will have modCount + + operation. The essence of enhancing for is to use the Iterator iterator of the set. Let's first look at the internal principle of iterators.
Entering the checkForComodification method, you can see that if the collection is modified during traversal, resulting in the change of modCount, a concurrent modification exception will be thrown.
However, the internal CopyOnWriteArrayList of JUC can modify the set in concurrency, but modifying the set in concurrency sacrifices consistency, and the data may not be up-to-date. CopyOnWriteArrayList is the final consistency. CopyOnWriteArrayList uses copy on write. Each write will use a new array, and then reference the members to the new array. Lock lock is added when modifying. For the and iterator, the current array of member variables will be obtained each time it is traversed. CopyOnWriteArrayList provides two methods to operate on the array storing data, namely getArray() and setArray().
Iterator for CopyOnWriteArrayList
The general process is like this
View several key methods
- Construction method
- add() method
public boolean add(E e) { // Use ReentrantLock lock lock final ReentrantLock lock = this.lock; lock.lock(); try { // getArray() gets the original array Object[] elements = getArray(); int len = elements.length; // Copied new array Object[] newElements = Arrays.copyOf(elements, len + 1); // Add new value newElements[len] = e; // The variable reference setArray(newElements); return true; } finally { lock.unlock(); } }
- The addIfAbsent method is used to add an element that is not in the collection (i.e. de duplication)
public boolean addIfAbsent(E e) { Object[] snapshot = getArray(); // indexOf can be regarded as a black box method to check whether there is e element in the collection. Returning - 1 indicates that there is no e element in the collection return indexOf(e, snapshot, 0, snapshot.length) >= 0 ? false : addIfAbsent(e, snapshot); } private boolean addIfAbsent(E e, Object[] snapshot) { final ReentrantLock lock = this.lock; lock.lock(); try { Object[] current = getArray(); int len = current.length; // The element of the array has been modified if (snapshot != current) { // Optimize for lost race to another addXXX operation int common = Math.min(snapshot.length, len); for (int i = 0; i < common; i++) // Indicates that the element at position i has been modified and is equal to e, which indicates that there is already this element in the array and returns false if (current[i] != snapshot[i] && eq(e, current[i])) return false; // Or check for e if (indexOf(e, current, common, len) >= 0) return false; } // The principle is the same as that of add method Object[] newElements = Arrays.copyOf(current, len + 1); newElements[len] = e; setArray(newElements); return true; } finally { lock.unlock(); } }
The CopyOnWriteArraySet is not implemented based on hash table, but based on CopyOnWriteArrayList. The last two methods are mainly used
Summary: these two concurrency safe collection classes are mainly used in the case of more reading and less writing.