• Java底层类和源码分析系列-CopyOnWriteArrayList底层架构和源码分析


    ArrayList是非线程安全的,Vector虽是线程安全的,但由于简单粗暴的锁同步机制,性能较差。而CopyOnWriteArrayList则提供了另一种不同的并发处理策略(当然是针对特定的并发场景)。

    很多时候,我们的系统应对的都是读多写少的并发场景。CopyOnWriteArrayList容器允许并发读,读操作是无锁的,性能较高。至于写操作,比如向容器中添加一个元素,则首先将当前容器复制一份,然后在新副本上执行写操作,结束之后再将原容器的引用指向新容器。

    几个要点

    • 在写时进行复制的线程安全ArrayList;
    • 适合读多写少的场景;
    • 读操作无锁;
    • 写操作则通过创建底层数组的新副本来实现,是一种读写分离的并发策略,阻塞写操作,读操作不会阻塞,实现读写分离;
    • 保证最终一致性;
    • 其底层数据结构也是数组;
    • 每次执行写操作都要将原容器拷贝一份,数据量大时,对内存压力较大,可能会引起频繁GC;二是无法保证实时性,Vector对于读写操作均加锁同步,可以保证读和写的强一致性;
    • CopyOnWriteArrayList默认容量是数组长度为1的Object类型数组;

    定义

    public class CopyOnWriteArrayList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable

    成员属性

        // 使用可重入锁进行加锁,保证线程安全
        final transient ReentrantLock lock = new ReentrantLock();
    
        // 底层数据结构,注意这里用volatile修饰,确定了多线程情况下的可见性
        private transient volatile Object[] array;
    
        // getter
        final Object[] getArray() {
            return array;
        }
        // setter
        final void setArray(Object[] a) {
            array = a;
        }

    构造方法

        public CopyOnWriteArrayList() {
        // 所有对array的操作都是通过setArray和getArray进行的
        setArray(new Object[0]);
    }
    
     public CopyOnWriteArrayList(Collection<? extends E> c) {
        Object[] elements;
        // 如果c是CopyOnWriteArrayList则把数组直接进行赋值,注意这里是浅拷贝,两个集合公用一个数组
        if (c.getClass() == CopyOnWriteArrayList.class)
            elements = ((CopyOnWriteArrayList<?>)c).getArray();
        else {
            elements = c.toArray();
            // c.toArray might (incorrectly) not return Object[] (see 6260652)
            if (elements.getClass() != Object[].class)
                elements = Arrays.copyOf(elements, elements.length, Object[].class);
        }
        setArray(elements);
    }

    get

    get
        // 直接无锁访问数组下标获取数据
        public E get(int index) {
            return get(getArray(), index);
        }
    
        private E get(Object[] a, int index) {
         return (E) a[index];
        }

    add

    // 向list中获取元素
    public boolean add(E e) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] elements = getArray();
            int len = elements.length;
            // 注意这里将数组长度加1
            Object[] newElements = Arrays.copyOf(elements, len + 1);
            // 新元素放在最后一位
            newElements[len] = e;
            setArray(newElements);
            return true;
        } finally {
            lock.unlock();
        }
    }
    
    // 更新指定下标的元素
        public E set(int index, E element) {
            // 获取公共锁
            final ReentrantLock lock = this.lock;
            // 加锁
            lock.lock();
            try {
                // 获取数组
                Object[] elements = getArray();
                // 获取数组插入位置的元素
                E oldValue = get(elements, index);
                // 当值不相等时进行更新
                if (oldValue != element) {
                    int len = elements.length;
                    // 拷贝数组
                    Object[] newElements = Arrays.copyOf(elements, len);
                    newElements[index] = element;
                    // 赋值给数组
                    setArray(newElements);
                } else {
                    // Not quite a no-op; ensures volatile write semantics
                    // 当值相同时,直接赋值
                    setArray(elements);
                }
                // 返回原来的值
                return oldValue;
            } finally {
                // 解锁
                lock.unlock();
            }
        }

    remove

    // 删除指定下标的元素
        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)
                    // 不需要移动时,代表删除的末尾元素
                    setArray(Arrays.copyOf(elements, len - 1));
                else {
                    // 实例化新的数组
                    Object[] newElements = new Object[len - 1];
                    // 先拷贝前一部分
                    System.arraycopy(elements, 0, newElements, 0, index);
                    // 再拷贝后一部分
                    System.arraycopy(elements, index + 1, newElements, index,
                                     numMoved);
                    // 赋值
                    setArray(newElements);
                }
                // 返回删除的值
                return oldValue;
            } finally {
                // 解锁
                lock.unlock();
            }
        }

    函数接口

       public void forEach(Consumer<? super E> action) {
            if (action == null) throw new NullPointerException();
            Object[] elements = getArray();
            int len = elements.length;
            for (int i = 0; i < len; ++i) {
                @SuppressWarnings("unchecked") E e = (E) elements[i];
                action.accept(e);//遍历执行Consumer
            }
        }
    
        public boolean removeIf(Predicate<? super E> filter) {
            if (filter == null) throw new NullPointerException();
            final ReentrantLock lock = this.lock;
            lock.lock();
            try {
                Object[] elements = getArray();
                int len = elements.length;
                if (len != 0) {
                    int newlen = 0;
                    Object[] temp = new Object[len];
                    for (int i = 0; i < len; ++i) {
                        @SuppressWarnings("unchecked") E e = (E) elements[i];
                        if (!filter.test(e))//验证Predicate
                            temp[newlen++] = e;
                    }
                    if (newlen != len) {
                        setArray(Arrays.copyOf(temp, newlen));
                        return true;
                    }
                }
                return false;
            } finally {
                lock.unlock();
            }
        }
    
        public void replaceAll(UnaryOperator<E> operator) {
            if (operator == null) throw new NullPointerException();
            final ReentrantLock lock = this.lock;
            lock.lock();
            try {
                Object[] elements = getArray();
                int len = elements.length;
                Object[] newElements = Arrays.copyOf(elements, len);
                for (int i = 0; i < len; ++i) {
                    @SuppressWarnings("unchecked") E e = (E) elements[i];
                    newElements[i] = operator.apply(e);
                }
                setArray(newElements);
            } finally {
                lock.unlock();
            }
        }
    
        public void sort(Comparator<? super E> c) {
            final ReentrantLock lock = this.lock;
            lock.lock();
            try {
                Object[] elements = getArray();
                Object[] newElements = Arrays.copyOf(elements, elements.length);
                @SuppressWarnings("unchecked") E[] es = (E[])newElements;
                Arrays.sort(es, c);
                setArray(newElements);
            } finally {
                lock.unlock();
            }
        }
  • 相关阅读:
    VUE16 检测数据变化的原理
    Pytorch入门
    Redis安装,可视化和配置
    Dapper库的学习参考
    LeetCode148. Sort List 单链表排序
    xcode 添加copy files 时签名失败
    Python 3网络爬虫开发实战崔庆才
    项目管理【79】 | 知识产权与标准规范政府采购法法
    项目管理【81】 | 项目立项管理
    项目管理【78】 | 知识产权与标准规范招投标法
  • 原文地址:https://www.cnblogs.com/starcrm/p/12706301.html
Copyright © 2020-2023  润新知