Date: October 18, 2017


CopyOnWrite

CopyOnWrite (short for COW) is a copy-on-write technology. CopyOnWriteArrayList and CopyOnWriteArraySet in Java use CopyOnWrite technology. When you add, modify, or delete elements to an internal array, you don’t operate directly on the original array. Instead, you first copy the container, then operate on the new container, and finally refer to the new container.

When you write more about data replication technology to view www.cnblogs.com/biyeymyhjob…

CopyOnWriteArrayList source code analysis

Since ArrayList is not thread safe, we usually choose CopyOnWriteArrayList to replace ArrayList in multithreaded environment to ensure that the program data is normal. CopyOnWriteArrayList is implemented in the following ways.

1. Add volatile to internal array attributes to ensure visibility and atomicity, but not to ensure visibility and atomicity of array elements.

2. Added a reentrant lock, which is locked in the add, modify, delete operation, but not in the read operation. Write operations (add, modify, delete) are not performed directly on the original array, but a copy of the new array, on the new array.

Because each write operation needs to copy a new array, additional memory consumption is increased, and lock synchronization is required, resulting in a high cost of each write, while the cost of read operation is relatively small. Therefore, it is more suitable for scenarios where the read and write operations are excessive and the batch write operation is recommended instead of multiple write operations to reduce the consumption caused by multiple write operations.

The constructor

The constructor primarily initializes the internal array, which is 0 by default.

/** * Sets the array. */
final void setArray(Object[] a) {
    array = a;
}

/** * Creates an empty list. */
public CopyOnWriteArrayList(a) {
    setArray(new Object[0]);
}
Copy the code

The add method

First copy the old array into the new array, then add the new element to the new array, and finally assign the new array to the internal array properties, and lock the whole process.

public boolean add(E e) {
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        Object[] elements = getArray();
        int len = elements.length;
        // Copy the old array into the new array
        Object[] newElements = Arrays.copyOf(elements, len + 1);
        // Add the new element to the end of the new array
        newElements[len] = e;
        // The inner array property points to the new array
        setArray(newElements);
        return true;
    } finally{ lock.unlock(); }}Copy the code

The get method

Directly retrieves the element of the corresponding index of the internal array. This procedure does not lock, so the element it returns may not be the latest data.

private E get(Object[] a, int index) {
    return (E) a[index];
}

/ * * * {@inheritDoc}
 *
 * @throws IndexOutOfBoundsException {@inheritDoc} * /
public E get(int index) {
    return get(getArray(), index);
}
Copy the code

The remove method

The implementation of this method is similar to the add method. The elements before and after the index are directly copied into the new array. Finally, the new array is assigned to the internal array attributes, and the whole process requires locking.

public E remove(int index) {
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        Object[] elements = getArray();
        int len = elements.length;
        E oldValue = get(elements, index);
        int numMoved = len - index - 1;
        if (numMoved == 0)
            // If the element removed is the last, only the element before the index is copied into the new array
            setArray(Arrays.copyOf(elements, len - 1));
        else {
            Object[] newElements = new Object[len - 1];
            // Copy the element before the index into the new array
            System.arraycopy(elements, 0, newElements, 0, index);
            // Copy the indexed elements into the new array
            System.arraycopy(elements, index + 1, newElements, index,
                             numMoved);
            // The inner array property points to the new array
            setArray(newElements);
        }
        return oldValue;
    } finally{ lock.unlock(); }}Copy the code

The iterator method

This method returns an instance of the COWIterator iterator that iterates over the old inner array, or a snapshot of the inner array, so the data it iterates over may not be the latest. Here is the constructor for the COWIterator iterator

private COWIterator(Object[] elements, int initialCursor) {
    cursor = initialCursor;
    snapshot = elements;
}
Copy the code

CopyOnWriteArraySet principle

CopyOnWriteArraySet implementation with the help of CopyOnWriteArrayList class, its internal contains a CopyOnWriteArrayList object AL, its implementation method is to call the method of al object. Here is part of the source code

public CopyOnWriteArraySet(a) {
    al = new CopyOnWriteArrayList<E>();
}
public int size(a) {
    return al.size();
}
public boolean add(E e) {
        // Add the element if it does not exist
    return al.addIfAbsent(e);
}
public boolean remove(Object o) {
    return al.remove(o);
}
Copy the code