Fork me on Gitee

CopyOnWriteArrayList

CopyOnWriteArrayList

CopyOnWriteArrayList诞生记

  • 代替Vector和SynchronizedList,就像ConcurrentHashMap代替SynchronizedMap的原因一样
  • Vector和SynchronizedList的锁的粒度太大,并发效率相对比较低,并且迭代时无法编辑
  • Copy-On-Write并发容器还包括CopyOnWriteArraySet,用来替代同步Set

CopyOnWriteArrayList使用场景

  • 读操作可以尽可能地快,而写即使慢一点也没有太大关系。
    • 读多写少:黑名单,每日更新;监听器:迭代操作远多于修改操作

CopyOnWriteArrayList读写操作

  • 回顾读写锁:读读共享、其他都互斥(写写互斥、读写互斥、写读互斥)
  • 读写锁规则的升级:读取是完全不用加锁的,并且更厉害的是,写入也不会阻塞读取操作。只要写入和写入之间需要进行同步等待。
public class CopyOnWriteArrayListDemo1 {
    public static void main(String[] args) {
//        ArrayList<String> list = new ArrayList<>();
        CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
        list.add("1");
        list.add("2");
        list.add("3");
        list.add("4");
        list.add("5");

        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()){
            System.out.println("list is "+list);
            String next = iterator.next();
            System.out.println(next);
            if(next.equals("2")){
                list.remove("5");
            }

        }
    }
}

实现原理

ArryaList之所以报错原因是

final void checkForComodification() {
    // expectedModCount 为创建迭代器时的值
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
  • CopyOnWrite的含义:拷贝一份数据到新的内存,将指针指向新的地址
    • 创建新副本、读写分离
    • “不可变”原理
    • 迭代的时候可能会出现数据过期问题

缺点

  • 数据一致性问题:CopyOnWrite容器只能保证数据的最终-致性,不能保证数据的实时一致性。所以如果你希望写入的数据,马上能读到,请不要使用CopyOnWrite容器:
  • 内存占用问题:因为CopyOnWrite的写是复制机制,所以在进行写操作的时候,内存里会同时驻扎两个对象的内存。

源码分析

  • 数据结构
  • get():可以看到,get方法直接获取元素信息

image-20240305230534832

  • set():加Lock锁,同时拷贝一份新的数组,将set的值放置新数组最后一个元素位置

image-20240305230648217

posted @ 2024-03-05 23:28  shine-rainbow  阅读(4)  评论(0编辑  收藏  举报