教你手写CopyOnWriteArrayList

前言

面试官:ArrayList线程不安全,怎么解决?

我:CopyOnWriteList

面试官:CopyOnWriteList的原理是什么?

我:@# <math xmlns="http://www.w3.org/1998/Math/MathML"> %^ </math>,F***

有感于面试官经常问,今天就深入了解一下这玩意的原理

实现

核心方法

  • get:根据index获取值
  • add:添加元素

原理

看了CopyOnWriteList的源码,发现其实现原理很简单,核心就是读写分离。

jdk源码

java 复制代码
public class CopyOnWriteArrayList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
    //...

    /**
     * Appends the specified element to the end of this list.
     *
     * @param e element to be appended to this list
     * @return {@code true} (as specified by {@link Collection#add})
     */
    public boolean add(E e) {
        synchronized (lock) {
            Object[] es = getArray();
            int len = es.length;
            es = Arrays.copyOf(es, len + 1);
            es[len] = e;
            setArray(es);
            return true;
        }
    }
    
    public E get(int index) {
        return elementAt(getArray(), index);
    }
    //...
}
    

读的时候直接读,写的时候复制一个新的数组,然后再写入。

个人代码实现

java 复制代码
public class MyCopyOnWriteList<T> {

    private ReentrantLock lock = new ReentrantLock();

    private volatile List<T> list = new ArrayList<>();

    public void add(T t) {
        lock.lock();
        try {
            ArrayList<T> temp = new ArrayList<>(list);
            temp.add(t);
            list = temp;
        } finally {
            lock.unlock();
        }
    }

    public T get(int index) {
        return list.get(index);
    }

    public int size() {
        return list.size();
    }

    /**
     * 测试代码
     */
    public static void main(String[] args) throws InterruptedException {
//        List<Integer> list = new ArrayList<>(); // 可以取消注释改行看看效果
        MyCopyOnWriteList<Integer> list = new MyCopyOnWriteList<>();
        for (int i = 0; i < 10; i++) {
            CompletableFuture.runAsync(() -> {
                for (int i1 = 0; i1 < 100; i1++) {
                    list.add(i1);
                }
            });

        }
        TimeUnit.SECONDS.sleep(2);

        // 理想值返回1000 , 若使用ArrayList则会返回小于1000的值
        System.out.println("end, list size = " + list.size());
    }
}

总结

虽然CopyOnWriteList的实现原理很简单,但是我们可以发现它重大的缺陷,就是add任意一个元素都会进行数组复制,可以说相当消耗内存了 ,CopyOnWriteList.add的空间复杂度是O(n),而ArrayList.add的空间复杂度是O(1)。所以在使用的时候要慎重考虑。

相关推荐
qq_12498707534 分钟前
基于springboot框架的小型饮料销售管理系统的设计与实现(源码+论文+部署+安装)
java·spring boot·后端·spring·毕业设计
我命由我1234510 分钟前
Python Flask 开发:在 Flask 中返回字符串时,浏览器将其作为 HTML 解析
服务器·开发语言·后端·python·flask·html·学习方法
IT_陈寒19 分钟前
JavaScript 性能优化:5个被低估的V8引擎技巧让你的代码提速50%
前端·人工智能·后端
想用offer打牌30 分钟前
数据库大事务有什么危害(面试版)
数据库·后端·架构
踏浪无痕39 分钟前
别再只会用 Feign!手写一个 Mini RPC 框架搞懂 Spring Cloud 底层原理
后端·面试·架构
用户695619440371 小时前
前后端分离VUE3+Springboot项目集成PageOffice核心代码
后端
rannn_1111 小时前
【Git教程】概述、常用命令、Git-IDEA集成
java·git·后端·intellij-idea
我家领养了个白胖胖1 小时前
向量化和向量数据库redisstack使用
java·后端·ai编程
嘻哈baby1 小时前
NextCloud私有云盘完整部署指南
后端
Ray661 小时前
Linux 日志处理三剑客:grep、awk、sed
后端