教你手写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)。所以在使用的时候要慎重考虑。

相关推荐
用户9186861286873 分钟前
从物流查询聊策略模式:后端开发中的多策略设计
后端
bcbnb37 分钟前
iOS开发中手动实现代码混淆的完整步骤与示例
后端·ios
河阿里40 分钟前
SpringBoot:项目启动速度深度优化
java·spring boot·后端
Code_Artist43 分钟前
线程池的终结?协程/纤程/虚拟线程带来的并发范式变化!
后端·架构·代码规范
阿丰资源1 小时前
基于SpringBoot的企业客户管理系统(附源码)
java·spring boot·后端
两年半的个人练习生^_^1 小时前
SpringBoot 项目使用 Jasypt 实现配置文件敏感信息加密
java·spring boot·后端
阿凡9807301 小时前
从零实现嘉立创 EDA 与 FreeCAD 的 PCB 双向实时协同
后端
AIData搭子1 小时前
一条命令迁移,一个记忆库共享——基于阿里云 Tablestore 的迁移实战指南来了,全文干货,赶紧收藏!
后端
Rust研习社2 小时前
开源项目里的 deny.toml 是什么?
后端·rust·编程语言
undefinedType2 小时前
PostgreSQL JIT 详细讲解
后端