并发容器之CopyOnWriteArrayList讲解

并发容器之CopyOnWriteArrayList讲解

CopyOnWriteArrayList是JUC工具包中的一个工具类,是属于线程安全的,其所有可变操作(add、set等等)都是通过对底层数组进行一次新的复制来实现的,它的特点是读操作的时候是不加锁的,写操作的时候会加锁,保证数据安全。

一.原理分析:直接上源码
我们先看一下其构造方法:其无参构造方法中,实际就算创建了一个transient volatile Object[] 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]);
    }

二.常用的方法
CopyOnWriteArrayList的方法有很多,本文仅分析一下常用的两个方法,其它更多的方法感兴趣的同学可以去细细品味一番,毕竟都是大神写的,读的越多,对提高自己的编码能力会有很大的帮助。
在这里插入图片描述

1.add()方法:
该方法实现了List的接口:boolean add(E e);
分析一下源码:在写入操作前,会使用当前类中的重入锁ReentrantLock对添加对象的逻辑进行加锁操作。
其加锁的逻辑是:先获取原理的数组elements ,计算出原数组的长度len,然后复制出一个新的数组,且长度在原数组的基础上+1;再将新数组下标为len(也就是新数组末尾)的值设置为要添加的对象e;最后再将新数组设置为最终数组对象。

	
    /**
     * 将指定的元素追加到此列表的末尾。
     */
    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()方法
其原理就很简单了,直接调用内部的get方法,获取数组对应下标的值即可,且该操作是不加锁的。

    @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);
    }

三.使用案例演示

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();
        }

    }
}

输出结果:

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

到此关于CopyOnWriteArrayList的分析就先告一段落了。
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_37488998/article/details/109707391