教你手写CopyOnWriteArrayList

前言

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

我:CopyOnWriteList

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

我:@# %^ ,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)。所以在使用的时候要慎重考虑。

相关推荐
苍何16 分钟前
让 WorkBuddy 操控浏览器,干活有点猛啊1
后端
IT_陈寒33 分钟前
当Java的hashCode遇上Lombok,我的缓存被全清了
前端·人工智能·后端
XW1 小时前
常用提示词(Prompt)框架总结
后端
ServBay1 小时前
DeepSeek 再次崩了,DeepSeek V5正在路上?
后端·deepseek
IT规划师2 小时前
编程术语中的同步与异步:从"等不等"到工程取舍
后端·面试
孟陬3 小时前
Foobar 技术周刊#159:当看不懂代码时,如何高效排障调试。脏页陷阱:一条只读查询,写入数 TB 数据。推测解码:大模型加速利器
前端·人工智能·后端
GoGeekBaird3 小时前
别再给每个 AI 做自我介绍了:我做了一个「个人上下文」管理系统
后端·github·agent
码事漫谈3 小时前
腾讯混元 Hy4 正式版发布了
后端
Mikko73 小时前
Redis 连接数满了服务端有错误信息吗?连接数不增加却命令超时?6.2 实测连接池、超时与大 key 怎么判定
java·spring boot·redis·后端
苍何4 小时前
DeepSeek的Super-agent 设计,和我们的工程实践
后端