1. CopyOnWriteArrayList,写数组的拷贝,支持高效率并发且是线程安全的,读操作无锁的ArrayList。所有可变操作都是通过对底层数组进行一次新的复制来实现。
  2. CopyOnWriteArrayList适合使用在读操作远远大于写操作的场景里,比如缓存。它不存在扩容的概念,每次写操作都要复制一个副本,在副本的基础上修改后改变Array引用。CopyOnWriteArrayList中写操作需要大面积复制数组,所以性能肯定很差
  3. 在迭代器上进行的元素更改操作(remove、set和add)不受支持。这些方法将抛出UnsupportedOperationException。

定义

CopyOnWriteArrayList跟ArrayList一样实现了List, RandomAccess, Cloneable, Serializable接口,但是没有继承AbstractList。

初始化时候新建一个容量为0的数组。

add(E e)方法

123456789101112131415161718192021
public boolean add(E e) { //获得锁,添加的时候首先进行锁定    final ReentrantLock lock = this.lock;    lock.lock();    try {     //获取当前数组        Object[] elements = getArray();        //获取当前数组的长度        int len = elements.length;        //这个是重点,创建新数组,容量为旧数组长度加1,将旧数组拷贝到新数组中        Object[] newElements = Arrays.copyOf(elements, len + 1);        //要添加的数据添加到新数组的末尾        newElements[len] = e;        //将数组引用指向新数组,完成了添加元素操作        setArray(newElements);        return true;    } finally {      //解锁        lock.unlock();    }}

从上面来说,每次添加一个新元素都会长度加1,然后复制整个旧数组,由此可见对于写多的操作,效率肯定不会很好。所以CopyOnWriteArrayList适合读多写少的场景。

add(int index, E element)方法

12345678910111213141516171819202122232425262728293031323334
public void add(int index, E element) {  //同样也是先加锁    final ReentrantLock lock = this.lock;    lock.lock();    try {        //获取旧数组        Object[] elements = getArray();        //获取旧数组长度        int len = elements.length;        //校验指定的index        if (index > len || index < 0)            throw new IndexOutOfBoundsException("Index: "+index+                                                ", Size: "+len);        Object[] newElements;        int numMoved = len - index;        if (numMoved == 0)//需要插入的位置正好等于数组长度,数组长度加1,旧数据拷贝到新数组            newElements = Arrays.copyOf(elements, len + 1);        else {         //新数组长度增加1            newElements = new Object[len + 1];            //分两次拷贝,第一次拷贝旧数组0到index处的到新数组0到index,第二次拷贝旧数组index到最后的数组到新数组index+1到最后            System.arraycopy(elements, 0, newElements, 0, index);            System.arraycopy(elements, index, newElements, index + 1,                             numMoved);        }        //index初插入数据        newElements[index] = element;        //新数组指向全局数组        setArray(newElements);    } finally {        //解锁        lock.unlock();    }}

set(int index, E element)方法

1234567891011121314151617181920212223242526272829
public E set(int index, E element) { //修改元素之前首先加锁    final ReentrantLock lock = this.lock;    lock.lock();    try {     //获取原来的数组        Object[] elements = getArray();        //index位置的元素        E oldValue = get(elements, index);        //新旧值不相等才进行替换        if (oldValue != element) {                //原来的长度            int len = elements.length;            //拷贝一份到新数组            Object[] newElements = Arrays.copyOf(elements, len);            //替换元素            newElements[index] = element;            //新数组指向全局数组            setArray(newElements);        } else {            // Not quite a no-op; ensures volatile write semantics            setArray(elements);        }        return oldValue;    } finally {     //解锁        lock.unlock();    }}

get(int index)方法

读的时候不加锁,代码如下:

123
public E get(int index) {    return get(getArray(), index);}
123
private E get(Object[] a, int index) {    return (E) a[index];}

remove()

remove方法不再过多介绍,看完add和set方法应该就能理解。

迭代

内部类COWIterator 实现了ListIterator接口。迭代的时候不能进行remove,add,set等方法,会抛异常。

迭代速度快,迭代时是迭代的数组快照。

12
/** Snapshot of the array */private final Object[] snapshot;

源码分析

jdk1.7.0_71

123456
//锁,保护所有存取器transient final ReentrantLock lock = new ReentrantLock();//保存数据的数组private volatile transient Object[] array;final Object[] getArray() {return array;}final void setArray(Object[] a) {array = a;}

空构造,初始化一个长度为0的数组

123
public CopyOnWriteArrayList() {        setArray(new Object[0]);    }

利用集合初始化一个CopyOnWriteArrayList

1
public CopyOnWriteArrayList(Collection<? extends E> c) {}

利用数组初始化一个CopyOnWriteArrayList

1
public CopyOnWriteArrayList(E[] toCopyIn) {}

size() 大小

1
public int size() {}

isEmpty()是否为空

1
public boolean isEmpty(){}

indexOf(Object o, Object[] elements,int index, int fence) 元素索引

1
private static int indexOf(Object o, Object[] elements,int index, int fence) {}

indexOf() 元素索引

1
public int indexOf(Object o){}

indexOf(E e, int index) 元素索引

1
public int indexOf(E e, int index) {}

lastIndexOf(Object o, Object[] elements, int index) 元素索引,最后一个

1
private static int lastIndexOf(Object o, Object[] elements, int index) {}

lastIndexOf(Object o) 元素索引,最后一个

1
public int indexOf(E e, int index) {}

lastIndexOf(E e, int index) 元素索引,最后一个

1
public int lastIndexOf(E e, int index) {}

contains(Object o) 是否包含元素

1
public boolean contains(Object o){}

clone() 浅拷贝

1
public Object clone() {}

toArray() 转换成数组

1
public Object[] toArray(){}

toArray(T a[]) 转换成指定类型的数组

1
public <T> T[] toArray(T a[]) {}

E get(int index)获取指定位置的元素

1
public E get(int index){}

set(int index, E element) 指定位置设置元素

写元素的时候,先获得锁,finall块中释放锁

123456789101112131415161718192021
public E set(int index, E element) {        final ReentrantLock lock = this.lock;        lock.lock();        try {            Object[] elements = getArray();            E oldValue = get(elements, index);

            if (oldValue != element) {                int len = elements.length;                Object[] newElements = Arrays.copyOf(elements, len);                newElements[index] = element;                setArray(newElements);            } else {                // Not quite a no-op; ensures volatile write semantics                setArray(elements);            }            return oldValue;        } finally {            lock.unlock();        }    }

add(E e) 元素添加到末尾

1
public boolean add(E e) {}

add(int index, E element) 指定位置之后插入元素

1
public void add(int index, E element){}

remove(int index)删除指定位置的元素

1
public E remove(int index) {}

remove(Object o) 删除第一个匹配的元素

1
public boolean remove(Object o) {}

removeRange(int fromIndex, int toIndex) 删除指定区间的元素

1
private void removeRange(int fromIndex, int toIndex) {}

addIfAbsent(E e) 如果元素不存在就添加进list中

1
public boolean addIfAbsent(E e){}

containsAll(Collection<?> c)是否包含全部

1
public boolean containsAll(Collection<?> c){}

removeAll(Collection<?> c) 移除全部包含在集合中的元素

1
public boolean removeAll(Collection<?> c){}

retainAll(Collection<?> c) 保留指定集合的元素,其他的删除

1
public boolean retainAll(Collection<?> c){}

addAllAbsent(Collection<? extends E> c) 如果不存在就添加进去

1
public int addAllAbsent(Collection<? extends E> c) {}

clear() 清空list

1
public void clear(){}

addAll(Collection<? extends E> c)添加集合中的元素到尾部

1
public void addAll(Collection<? extends E> c){}

addAll(int index, Collection<? extends E> c) 添加集合中元素到指定位置之后

1
public boolean addAll(int index, Collection<? extends E> c){}

toString()

1
public String toString(){}

equals(Object o)

1234567891011121314151617
public boolean equals(Object o) {        if (o == this)            return true;        if (!(o instanceof List))            return false;

        List<?> list = (List<?>)(o);        Iterator<?> it = list.iterator();        Object[] elements = getArray();        int len = elements.length;        for (int i = 0; i < len; ++i)            if (!it.hasNext() || !eq(elements[i], it.next()))                return false;        if (it.hasNext())            return false;        return true;    }

hashCode()

1
public int hashCode{}

listIterator(final int index)和 listIterator() 返回一个迭代器,支持向前和向后遍历

123
public ListIterator<E> listIterator(final int index) {}

public ListIterator<E> listIterator() {}

iterator() 只能向后遍历

1
public Iterator<E> iterator() {}

subList() 返回部分list

12345
public List<E> subList(int fromIndex, int toIndex) { ...   return new COWSubList<E>(this, fromIndex, toIndex); ...}

参考

http://www.cnblogs.com/sunwei2012/archive/2010/10/08/1845656.html

http://my.oschina.net/jielucky/blog/167198

转载于:https://www.cnblogs.com/zhangboyu/p/7452542.html

CopyOnWriteArrayList简介相关推荐

  1. Copy-On-Write容器之一:CopyOnWriteArrayList

    一.CopyOnWriteArrayList简介 为了维护对象的一致性快照,要依靠不可变性(immutability)来消除在协调读取不同的但是相关的属性时需要的同步.对于集合,这意味着如果有大量的读 ...

  2. 第四篇:走近CopyOnWriteArrayList(基于JDK1.8)

    CopyOnWriteArrayList简介 熟悉Java开发的童鞋都知道ArrayList是线程不安全的,在多线程的环境下可能会发生fast-fail机制,抛出ConcurrentModificat ...

  3. 面对互联网裁员潮,我们该怎么提升自己核心知识能力

    近日,互联网行业的裁员潮愈演愈烈,之前还是香饽饽的行业,突然来了一拨釜底抽薪,属实让人难以接受,很多人还处在一个懵逼的状态.就连曾经说不会开除任何一个兄弟的某东,也开始了一波裁员潮.在这样的大环境下, ...

  4. Java中高级核心知识

    前言: java是一门面向对象的编程语言,功能强大.简单易用,可以编写桌面应用程序.Web应用程序.分布式系统和嵌入式系统应用程序等. 在Java简单入门之后很多人不知道下一阶段该做什么,对自己的学习 ...

  5. 资料搜集-JAVA系统的梳理知识6-JAVA多线程

    点击关注[公众号](#公众号 "公众号")及时获取笔主最新更新文章,并可免费领取本文档配套的<Java 面试突击>以及 Java 工程师必备学习资源.<!-- T ...

  6. copyof java_死磕 java集合之CopyOnWriteArrayList源码分析

    简介 CopyOnWriteArrayList是ArrayList的线程安全版本,内部也是通过数组实现,每次对数组的修改都完全拷贝一份新的数组来修改,修改完了再替换掉老数组,这样保证了只阻塞写操作,不 ...

  7. 学会了CopyOnWriteArrayList可以再多和面试官对线三分钟

    ArrayList是大家用的再熟悉不过的集合了,而此集合设计之初也是为了高效率,并未考虑多线程场景下,所以也就有了多线程下的CopyOnWriteArrayList这一集合 回忆下ArrayList ...

  8. JAVA之容器类简介

    一.容器简介 容器是一个将多个元素组合到一个单元的对象,是代表一组对象的对象,容器中的对象成为它的元素.容器适用于处理各种类型的对象的聚集,例如存储.获取.操作聚合数据,以及聚合数据的通信.容器只保存 ...

  9. etcd 笔记(01)— etcd 简介、特点、应用场景、常用术语、分布式 CAP 理论、分布式原理

    1. etcd 简介 etcd 官网定义: A highly-available key value store for shared configuration and service discov ...

最新文章

  1. hashMap传入参数,table长度为多少
  2. 阔力梯的树(2020 CCPC Wannafly Winter Camp Day2 Div.12 )dsu on tree
  3. 设置弹性框项目之间距离的更好方法
  4. SpringBoot-04:SpringBoot在idea中的俩种创建方式
  5. Mysql 练习 总结
  6. 使用GNS3简单模拟帧中继环境
  7. AAAI 2022 | 可解释和鲁棒的联合文本分类及证据提取
  8. hibernate mysql autocommit_Hibernate4 中为什么我没有用commit()方法直接用save就存到数据库了?...
  9. php匹配中文最准确的正则表达式
  10. Django安装与开发虚拟环境搭建01
  11. 2020 年 9 月程序员工资统计,新出炉!
  12. 29.优化 MySQL Server
  13. java安卓软件开发菜鸟教程,Android 开发环境搭建
  14. 单片机仿真软件proteus8安装与使用
  15. RingBuffer
  16. AG-DST论文笔记
  17. 计算机硬盘有磁性材料吗,电脑硬盘里有磁铁吗
  18. 阿里云云计算助理工程师认证(ACA)
  19. 史上最简单的openshift免费空间上传代码教程!没有之一!
  20. AI 仿人类人工智能(超级智能)的本质

热门文章

  1. 48.动态分区匹配算法(连续分区)
  2. System.Windows.Forms命名空间的MessageBox.show()用法大全
  3. 中心频率和一些概念解释
  4. java 有序列表_关于算法:在Java中为列表列表生成唯一的有序非重复组合
  5. vs2019键盘钩子_C#键盘按键监视
  6. flink sql udf jar包_flink教程flink 1.11 集成zeppelin实现简易实时计算平台
  7. JDBC中的Statement 和PreparedStatement的区别?
  8. 跨域加了header也解决不了?
  9. linux卸载minicom,ubuntu下minicom超级终端的使用方法
  10. centos6 配置ip、服务