CopyOnWriteArrayList简介
- CopyOnWriteArrayList,写数组的拷贝,支持高效率并发且是线程安全的,读操作无锁的ArrayList。所有可变操作都是通过对底层数组进行一次新的复制来实现。
- CopyOnWriteArrayList适合使用在读操作远远大于写操作的场景里,比如缓存。它不存在扩容的概念,每次写操作都要复制一个副本,在副本的基础上修改后改变Array引用。CopyOnWriteArrayList中写操作需要大面积复制数组,所以性能肯定很差
- 在迭代器上进行的元素更改操作(remove、set和add)不受支持。这些方法将抛出UnsupportedOperationException。
定义
CopyOnWriteArrayList跟ArrayList一样实现了List, RandomAccess, Cloneable, Serializable接口,但是没有继承AbstractList。
初始化时候新建一个容量为0的数组。
add(E e)方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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 |
public boolean add(E e) {
|
从上面来说,每次添加一个新元素都会长度加1,然后复制整个旧数组,由此可见对于写多的操作,效率肯定不会很好。所以CopyOnWriteArrayList适合读多写少的场景。
add(int index, E element)方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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)方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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)方法
1 |
public void add(int index, E element) {
|
1 |
public E set(int index, E element) {
|
get(int index)方法
读的时候不加锁,代码如下:
1 |
public E get(int index) {
|
1 |
private E get(Object[] a, int index) {
|
remove()
remove方法不再过多介绍,看完add和set方法应该就能理解。
迭代
内部类COWIterator 实现了ListIterator接口。迭代的时候不能进行remove,add,set等方法,会抛异常。
迭代速度快,迭代时是迭代的数组快照。
1 |
/** Snapshot of the array */ |
源码分析
jdk1.7.0_71
1
2
3
4
5
6
//锁,保护所有存取器
transient final ReentrantLock lock = new ReentrantLock();
//保存数据的数组
private volatile transient Object[] array;
final Object[] getArray() {return array;}
final void setArray(Object[] a) {array = a;}
空构造,初始化一个长度为0的数组
1
2
3
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块中释放锁
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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){}
c)是否包含全部" style="color: rgb(85, 85, 85); text-decoration: none; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: rgb(204, 204, 204); word-wrap: break-word; background-color: transparent;">containsAll(Collection<?> c)是否包含全部
1
public boolean containsAll(Collection<?> c){}
c) 移除全部包含在集合中的元素" style="color: rgb(85, 85, 85); text-decoration: none; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: rgb(204, 204, 204); word-wrap: break-word; background-color: transparent;">removeAll(Collection<?> c) 移除全部包含在集合中的元素
1
public boolean removeAll(Collection<?> c){}
c) 保留指定集合的元素,其他的删除" style="color: rgb(85, 85, 85); text-decoration: none; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: rgb(204, 204, 204); word-wrap: break-word; background-color: transparent;">retainAll(Collection<?> c) 保留指定集合的元素,其他的删除
1
public boolean retainAll(Collection<?> c){}
c) 如果不存在就添加进去" style="color: rgb(85, 85, 85); text-decoration: none; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: rgb(204, 204, 204); word-wrap: break-word; background-color: transparent;">addAllAbsent(Collection<? extends E> c) 如果不存在就添加进去
1
public int addAllAbsent(Collection<? extends E> c) {}
clear() 清空list
1
public void clear(){}
c)添加集合中的元素到尾部" style="color: rgb(85, 85, 85); text-decoration: none; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: rgb(204, 204, 204); word-wrap: break-word; background-color: transparent;">addAll(Collection<? extends E> c)添加集合中的元素到尾部
1
public void addAll(Collection<? extends E> c){}
c) 添加集合中元素到指定位置之后" style="color: rgb(85, 85, 85); text-decoration: none; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: rgb(204, 204, 204); word-wrap: break-word; background-color: transparent;">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)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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() 返回一个迭代器,支持向前和向后遍历
1
2
3
public ListIterator<E> listIterator(final int index) {}
public ListIterator<E> listIterator() {}
iterator() 只能向后遍历
1
public Iterator<E> iterator() {}
subList() 返回部分list
1
2
3
4
5
public List<E> subList(int fromIndex, int toIndex) {
...
return new COWSubList<E>(this, fromIndex, toIndex);
...
}
参考
jdk1.7.0_71
1 |
//锁,保护所有存取器 |
1 |
public CopyOnWriteArrayList() {
|
1 |
public CopyOnWriteArrayList(Collection<? extends E> c) {}
|
1 |
public CopyOnWriteArrayList(E[] toCopyIn) {}
|
1 |
public int size() {}
|
1 |
public boolean isEmpty(){}
|
1 |
private static int indexOf(Object o, Object[] elements,int index, int fence) {}
|
1 |
public int indexOf(Object o){}
|
1 |
public int indexOf(E e, int index) {}
|
1 |
private static int lastIndexOf(Object o, Object[] elements, int index) {}
|
1 |
public int indexOf(E e, int index) {}
|
1 |
public int lastIndexOf(E e, int index) {}
|
1 |
public boolean contains(Object o){}
|
1 |
public Object clone() {}
|
1 |
public Object[] toArray(){}
|
1 |
public <T> T[] toArray(T a[]) {}
|
1 |
public E get(int index){}
|
写元素的时候,先获得锁,finall块中释放锁
1 |
public E set(int index, E element) {
|
1 |
public boolean add(E e) {}
|
1 |
public void add(int index, E element){}
|
1 |
public E remove(int index) {}
|
1 |
public boolean remove(Object o) {}
|
1 |
private void removeRange(int fromIndex, int toIndex) {}
|
1 |
public boolean addIfAbsent(E e){}
|
1 |
public boolean containsAll(Collection<?> c){}
|
1 |
public boolean removeAll(Collection<?> c){}
|
1 |
public boolean retainAll(Collection<?> c){}
|
1 |
public int addAllAbsent(Collection<? extends E> c) {}
|
1 |
public void clear(){}
|
1 |
public void addAll(Collection<? extends E> c){}
|
1 |
public boolean addAll(int index, Collection<? extends E> c){}
|
1 |
public String toString(){}
|
1 |
public boolean equals(Object o) {
|
1 |
public int hashCode{}
|
1 |
public ListIterator<E> listIterator(final int index) {}
|
1 |
public Iterator<E> iterator() {}
|
1 |
public List<E> subList(int fromIndex, int toIndex) {
|
http://www.cnblogs.com/sunwei2012/archive/2010/10/08/1845656.html
CopyOnWriteArrayList简介的更多相关文章
- java多线程系列12 ConcurrentHashMap CopyOnWriteArrayList 简介
我们知道 ,hashmap 和 arraylist 是线程不安全的 在多线程环境下有数据安全问题, 当然 我们可以通过Collections的一些方法把他们变成线程安全的, Collections.s ...
- J.U.C并发框架源码阅读(十五)CopyOnWriteArrayList
基于版本jdk1.7.0_80 java.util.concurrent.CopyOnWriteArrayList 代码如下 /* * Copyright (c) 2003, 2011, Oracle ...
- java多线程系列 目录
Java多线程系列1 线程创建以及状态切换 Java多线程系列2 线程常见方法介绍 Java多线程系列3 synchronized 关键词 Java多线程系列4 线程交互(wait和 ...
- java_guide_9-30_并发相关
3.1 CopyOnWriteArrayList 简介 public class CopyOnWriteArrayList<E> extends Object implements Lis ...
- Java集合容器简介
Java集合容器主要有以下几类: 1,内置容器:数组 2,list容器:Vetor,Stack,ArrayList,LinkedList, CopyOnWriteArrayList(1.5),Attr ...
- CompletionService 简介
以下是jdk关于CompletionService的简介: public interface CompletionService<V> 将生产新的异步任务与使用已完成任务的结果分离开来的服 ...
- Java并发包中CopyOnWrite容器相关类简介
简介: 本文是主要介绍,并发容器CopyOnWriteArrayList和CopyOnWriteArraySet(不含重复元素的并发容器)的基本原理和使用示例. 欢迎探讨,如有错误敬请指正 如需转载, ...
- 死磕 java集合之CopyOnWriteArrayList源码分析
欢迎关注我的公众号"彤哥读源码",查看更多源码系列文章, 与彤哥一起畅游源码的海洋. 简介 CopyOnWriteArrayList是ArrayList的线程安全版本,内部也是通过 ...
- JDBC驱动程序注册 JDBC简介(二)
使用JDBC进行数据库操作的第一步就是驱动注册(当然你得先导入JAR). 驱动注册有多种方式,第一步必然是获得正确的驱动名称与URL格式 驱动名称与URL格式 RDBMS 驱动程序名称 ...
随机推荐
- rails常用命令备忘
rails new xxx 创建一个新rails项目 rails generate scaffold xxx 创建表模型,视图,控制器和迁移的"脚手架" rake db:migra ...
- Salesforce的数据权限机制
本文主要介绍了 Salesforce 对于系统中数据的访问控制是如何设计的,然后也了解了下 Alfresco 和 Oracle VPD 的数据权限机制.希望对一些业务系统的数据权限的访问控制设计能有所 ...
- Java小技巧输出26个英文字母
相信有的童鞋写到过与字母有关的小东西,是否有写过全部的字母呢?26个这么多字母,一个个打会疯掉.所有咱们可以用一个小技巧使用for循环帮我们把26个字母自动搞出来,大家来瞅一眼把! 使用Java遍历2 ...
- 【深度学习】目标检测算法总结(R-CNN、Fast R-CNN、Faster R-CNN、FPN、YOLO、SSD、RetinaNet)
目标检测是很多计算机视觉任务的基础,不论我们需要实现图像与文字的交互还是需要识别精细类别,它都提供了可靠的信息.本文对目标检测进行了整体回顾,第一部分从RCNN开始介绍基于候选区域的目标检测器,包括F ...
- GitHub上整理的一些资料
技术站点 Hacker News:非常棒的针对编程的链接聚合网站 Programming reddit:同上 MSDN:微软相关的官方技术集中地,主要是文档类 infoq:企业级应用,关注软件开发领域 ...
- JVM笔记9-Class类文件结构
1.Class类文件结构 Class 文件是一组以 8 位字节为基础单位的二进制流,各个数据项目严格按照顺序紧凑地排列在 Class 文件之中,中间没有添加任何分隔符,这使得整个 Class 文件中 ...
- IDEA安装教程
1.下载安装程序A,链接:https://pan.baidu.com/s/1IAsGDbApfyNsHuS7_m0rdw 密码:fthp 2.下载一个配置程序B,下载安装之后,暂时不用管,之后会用到. ...
- i++ 和 ++i;&& 和 &
一.算数运算符(自增运算符i++.自减运算符i++) ※ i++是先赋值(计算)再加1 :++i是先加1再赋值(计算) : int m = 5; boolean bool = ++m > 5 ...
- Robot framework(RF) Builti,Screenshot和Collections标准库介绍
1.1 Builti标准类库 在学习一门编程语言的时候,大多教材都是从打印“hello world”开始.我们可以像编程语言一样来学习Robot Framework.虽然通过RIDE 提供“填表”一 ...
- ELK 架构之 Elasticsearch 和 Kibana 安装配置
阅读目录: 1. ELK Stack 简介 2. 环境准备 3. 安装 Elasticsearch 4. 安装 Kibana 5. Kibana 使用 6. Elasticsearch 命令 最近在开 ...