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

相关推荐
拖孩5 分钟前
一个全程 AI 写的小程序「厨菜记」,上线 20 天跑通流量主,收入几块钱,开心得不行
前端·后端·微信小程序
颜进强8 分钟前
21 · NestJs AsyncProviders 异步提供者:useFactory 返回 Promise 之后,容器发生了什么
前端·后端·ai编程
Mikko711 分钟前
JVM 线上排查实战(七):jps 看不到进程、jstack 报不允许的操作怎么办?attach 失败的六种情况实测
java·运维·jvm·后端
小宋102124 分钟前
Agent 工具升级如何不破坏线上:Tool Schema 版本兼容与契约测试
java·人工智能·后端·spring
geovindu30 分钟前
rust: Flyweight Pattern
开发语言·后端·设计模式·rust·享元模式·结构型模式
我的xiaodoujiao31 分钟前
Django 基础知识详细图文教程 13-Django 模型定义与使用 3
数据库·后端·python·测试工具·oracle·django
SimonKing33 分钟前
QClaw关停之后:一个工具的退场,一段关系的告别
java·后端·程序员
不一样的少年_1 小时前
别用前端思维写后端:一张 5MB 图片,为什么能撑爆内存?
前端·后端·图片资源
夜之眷属1 小时前
记一次战斗服务器 CPU 打满 100% 且“无法恢复“的排查
java·linux·运维·服务器·后端·性能优化
郝学胜-神的一滴1 小时前
C++ Templates 07:编译报错和调试手段与实战技巧
开发语言·c++·后端·软件工程·visual studio