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

相关推荐
姜学迁18 分钟前
Rust-枚举
开发语言·后端·rust
【D'accumulation】1 小时前
令牌主动失效机制范例(利用redis)注释分析
java·spring boot·redis·后端
2401_854391081 小时前
高效开发:SpringBoot网上租赁系统实现细节
java·spring boot·后端
Cikiss1 小时前
微服务实战——SpringCache 整合 Redis
java·redis·后端·微服务
Cikiss1 小时前
微服务实战——平台属性
java·数据库·后端·微服务
OEC小胖胖1 小时前
Spring Boot + MyBatis 项目中常用注解详解(万字长篇解读)
java·spring boot·后端·spring·mybatis·web
2401_857617622 小时前
SpringBoot校园资料平台:开发与部署指南
java·spring boot·后端
计算机学姐2 小时前
基于SpringBoot+Vue的在线投票系统
java·vue.js·spring boot·后端·学习·intellij-idea·mybatis
Yvemil73 小时前
MQ 架构设计原理与消息中间件详解(二)
开发语言·后端·ruby
2401_854391083 小时前
Spring Boot大学生就业招聘系统的开发与部署
java·spring boot·后端