Explanation of CopyOnWriteArrayList of concurrent containers

Explanation of CopyOnWriteArrayList of concurrent containers

CopyOnWriteArrayList is a tool class in the JUC toolkit, which is thread-safe. All of its variable operations (add, set, etc.) are implemented by a new copy of the underlying array. It is characterized by read operations It is not locked when writing, and it is locked when writing to ensure data security.

1. Principle analysis: directly on the source code
Let’s take a look at its construction method: in its no-parameter construction method, it actually creates a transient volatile Object[] array array;

/** The array, accessed only via getArray/setArray. */
    private transient volatile Object[] array;

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

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


There are many commonly used methods CopyOnWriteArrayList. This article only analyzes the two commonly used methods. Students who are interested in more other methods can go and savor them. After all, they are written by the great gods. The more you read, It will be of great help to improve your coding ability.
Insert picture description here

1.add() method :
This method implements the List interface: boolean add(E e);
analyze the source code: before the write operation, the reentrant lock ReentrantLock in the current class will be used to lock the logic of adding objects operating.
The locking logic is: first obtain the principle array elements, calculate the length len of the original array, and then copy a new array with the length +1 on the basis of the original array; then subscript the new array as len (also That is, the value at the end of the new array is set to the object e to be added; finally, the new array is set as the final array object.

	
    /**
     * 将指定的元素追加到此列表的末尾。
     */
    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();
        }
    }

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

2.get() method
The principle is very simple, just call the internal get method directly to get the value of the corresponding subscript of the array, and the operation is not locked.

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

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

3. Use case demonstration

package com.demo.spring.test.baseThread.并发容器;

import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @Description: juc包中的线程并发容器
 * @Author: yangshilei
 */
public class CopyOnWriteArrayListDemo implements Runnable{
    
    

	// 创建一个静态类成员变量:CopyOnWriteArrayList
    private static List<Integer> copyOnWriteArrayList = new CopyOnWriteArrayList<>();
    // 定义一个倒数计数器,方便控制后面main线程和该类线程的日志展示效果;
    private CountDownLatch countDownLatch;

    public CopyOnWriteArrayListDemo(CountDownLatch countDownLatch){
    
    
        this.countDownLatch = countDownLatch;
    }

    @Override
    public void run() {
    
    
        synchronized (this){
    
     // 如果不加锁,下面的输出结果可能会存在重复的值
            copyOnWriteArrayList.add(1);
            System.out.println(Thread.currentThread().getName()+":"+copyOnWriteArrayList.size());
            countDownLatch.countDown();
        }
    }

    public static void main(String[] args) {
    
    
        ExecutorService pool = Executors.newFixedThreadPool(20);
        CountDownLatch countDownLatch = new CountDownLatch(50);
        CopyOnWriteArrayListDemo demo = new CopyOnWriteArrayListDemo(countDownLatch);
        try {
    
    
            for(int i = 0;i<50;i++){
    
    
                pool.execute(demo);
            }
            try {
    
    
            	// 此处进行线程等待,线程任务没有执行完成不打印下面main线程方法的输出结束语句。
                countDownLatch.await();
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
            System.out.println("the end "+copyOnWriteArrayList.size());
        }finally {
    
    
        	// 关闭线程池
            pool.shutdown();
        }

    }
}

Output result:

pool-1-thread-1:1
pool-1-thread-3:2
pool-1-thread-4:3
pool-1-thread-7:4
pool-1-thread-2:5
pool-1-thread-3:6
pool-1-thread-1:7
pool-1-thread-20:8
pool-1-thread-19:9
pool-1-thread-16:10
pool-1-thread-15:11
pool-1-thread-12:12
pool-1-thread-12:13
pool-1-thread-11:14
pool-1-thread-5:15
pool-1-thread-8:16
pool-1-thread-8:17
pool-1-thread-8:18
pool-1-thread-8:19
pool-1-thread-8:20
pool-1-thread-8:21
pool-1-thread-5:22
pool-1-thread-11:23
pool-1-thread-11:24
pool-1-thread-11:25
pool-1-thread-11:26
pool-1-thread-11:27
pool-1-thread-11:28
pool-1-thread-11:29
pool-1-thread-11:30
pool-1-thread-11:31
pool-1-thread-11:32
pool-1-thread-12:33
pool-1-thread-15:34
pool-1-thread-16:35
pool-1-thread-19:36
pool-1-thread-20:37
pool-1-thread-1:38
pool-1-thread-3:39
pool-1-thread-2:40
pool-1-thread-7:41
pool-1-thread-4:42
pool-1-thread-9:43
pool-1-thread-10:44
pool-1-thread-6:45
pool-1-thread-8:46
pool-1-thread-14:47
pool-1-thread-17:48
pool-1-thread-13:49
pool-1-thread-18:50
the end 50

So far, the analysis about CopyOnWriteArrayList comes to an end.
Insert picture description here

Guess you like

Origin blog.csdn.net/qq_37488998/article/details/109707391