CopyOnWriteArrayList分析
ArrayList是比较常用的一个可变大小的数组集合,但是是不能同步的。如果多个线程同时访问一个ArrayList实例,其中至少一个线程从结构上修改了列表,那么它必须保持外部同步。一般通过加锁对象进行同步操作来完成,如果不存在这样的对象,则应该使用 Collections.synchronizedList 方法将该列表“包装”起来:
List list = Collections.synchronizedList(new ArrayList(...));
此类的 iterator 和 listIterator 方法返回的迭代器是快速失败的:在创建迭代器之后,除非通过迭代器自身的 remove 或 add 方法从结构上对列表进行修改,否则在任何时间以任何方式对列表进行修改,迭代器都会抛出 ConcurrentModificationException。因此,面对并发的修改,迭代器会完全失败,而不是冒着在将来某个不确定时间发生任意不确定行为的风险。
CopyOnWriteArrayList是ArrayList的一个线程安全的变体实现,即可在多线程并发环境中使用。而它的可变操作都是通过对ArrayList中存储的数组通过一次新的复制来实现的。 当对列表进行修改(add,remove等)操作时,先lock,然后copy一份,也就是先复制一份当前的数据存储结构,然后进行相应的操作。这也就让get操作从同步中释放出来。因为对数据的改变会在副本中进行,所以不需要同步,只是有可能独到脏数据,但这对于某些应用来说,问题不大,适合于少量写大量读取的情况。
CopyOnWriteArrayList使用
CopyOnWriteArrayList数据结构比较简单,举个例子介绍它的用法:
List<String> list =new CopyOnWriteArrayList<String>();
list.add("4");
list.add("5");
list.add("6");
list.remove(2);
内部实现
CopyOnWriteArrayList内部采用的存储结构是数组,且在操作时用ReentrantLock进行锁操作:
transient final ReentrantLock lock = new ReentrantLock();
private volatile transient Object[] array;
CopyOnWriteArrayList的构造函数
CopyOnWriteArrayList提供了一些构造函数,下面是两个典型的函数
public CopyOnWriteArrayList() {
setArray(new Object[0]);//采用长度为0的数组
}
public CopyOnWriteArrayList(E[] toCopyIn) {
setArray(Arrays.copyOf(toCopyIn, toCopyIn.length, Object[].class));
}
Arrays.copyOf内部使用System.arraycopy函数拷贝数据,因为System,arraycopy函数是native的,效率比自己写的数组拷贝效率高。
CopyOnWriteArrayList的get函数
Get函数比较简单,直接返回指定位置的元素。
public E get(int index) {
return (E)(getArray()[index]);
}
CopyOnWriteArrayList的add函数
add函数添加之前,先加锁创建一个数组,数组长度在当前基础上加1,同时复制所有旧数组数据到新数组,然后在新数组的最后一个位置,添加新数据。然后将该新数组的引用赋予当前数组,最后解锁
public boolean add(E e) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len + 1);
newElements[len] = e;
setArray(newElements);
return true;
} finally {
lock.unlock();
}
}
CopyOnWriteArrayList的remove函数
remove函数跟add函数过程相似:先创建一个新的数组(长度为 原来长度-1),然后复制元素两边的数据元素, 然后将该新数组的引用赋予当前数组,整个过程也是有锁的。
public E remove(int index) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
Object oldValue = elements[index];
int numMoved = len - index - 1;
if (numMoved == 0)//
setArray(Arrays.copyOf(elements, len - 1));
else {
Object[] newElements = new Object[len - 1];
System.arraycopy(elements, 0, newElements, 0, index);
System.arraycopy(elements, index + 1, newElements, index,
numMoved);
setArray(newElements);
}
return (E)oldValue;
} finally {
lock.unlock();
}
}
比较ArrayList和CopyOnWriteArrayList
单线程:在元素较少的景象下,两个类的性能接近,当元素很多时,CopyOnWriteArrayList增长元素的操作会差一点。
多线程:跟着元素数量和线程数量的增长,CopyOnWriteArrayList在添加和删除元素的机能就会降落,并且比ArrayList机能低。但在查找元素时在元素数量和线程数量的增长的情况下性能比ArrayList好。
在读多写少的并发场景中,CopyOnWriteArrayList比ArrayList有着性能大的优势,是一个不错的选择。
CopyOnWriteArrayList分析的更多相关文章
- Java并发集合(一)-CopyOnWriteArrayList分析与使用
CopyOnWriteArrayList分析与使用 原文链接: http://ifeve.com/java-copy-on-write/ 一.Copy-On-Write Copy-On-Write简称 ...
- CopyOnWriteArrayList分析——能解决什么问题
CopyOnWriteArrayList主要可以解决的问题是并发遍历读取无锁(通过Iterator) 对比CopyOnWriteArrayList和ArrayList 假如我们频繁的读取一个可能会变化 ...
- Java CopyOnWriteArrayList分析
CopyOnWriteArrayList是一种线程安全的ArrayList,顾名思义,它会利用写时拷贝技术,它对共享对象做仅仅读操作的时候,大家都用一个共享对象,假设有可变的操作时,就会复制一份出来, ...
- java基础解析系列(八)---fail-fast机制及CopyOnWriteArrayList的原理
fail-fast机制及CopyOnWriteArrayList的原理 目录 java基础解析系列(一)---String.StringBuffer.StringBuilder java基础解析系列( ...
- ArrayList的ConcurrentModificationException异常和多线程下的异常
一.ConcurrentModificationException ArrayList源码看为什么出现异常: public class ArrayList<e> extends Abstr ...
- 多线程JUC并发篇常见面试详解
@ 目录 1.JUC 简介 2.线程和进程 3.并非与并行 4.线程的状态 5.wait/sleep的区别 6.Lock 锁(重点) 1.Lock锁 2.公平非公平: 3.ReentrantLock ...
- 【JUC】JDK1.8源码分析之CopyOnWriteArrayList(六)
一.前言 由于Deque与Queue有很大的相似性,Deque为双端队列,队列头部和尾部都可以进行入队列和出队列的操作,所以不再介绍Deque,感兴趣的读者可以自行阅读源码,相信偶了Queue源码的分 ...
- jdk并发包 CopyOnWriteArrayList源代码分析
CopyOnWriteArrayList是jdk1.5并法包里面用于处理高并发下.读多写少的情况下.减少锁等待的集合类.以下对该类实现做一个简要的分析 1,首先CopyOnWriteArrayList ...
- CopyOnWriteArrayList实现原理及源码分析
CopyOnWriteArrayList是Java并发包中提供的一个并发容器,它是个线程安全且读操作无锁的ArrayList,写操作则通过创建底层数组的新副本来实现,是一种读写分离的并发策略,我们也可 ...
随机推荐
- 应用LR监控Apache性能
1)对Apache服务器中的http.conf进行如下配置修改Apache中Httpd.conf文件,添加如下代码(该文件中都有,只要取消注释就好了)<Location /server-stat ...
- 巧用FTP命令进行文件传输
巧用FTP进行文件传输 Internet作为现代信息高速公路已深入我们的生活,其中它所提供的电子邮件Web网站信息服务已被越来越多的人所熟知和使用.FTP作为Internet的功能之一,虽然没有像 ...
- [机器学习实战] k邻近算法
1. k邻近算法原理: 存在一个样本数据集,也称作训练样本集,并且样本集中每个数据都存在标签,即我们知道样本集中每一数据与所属分类的对应关系.输入没有标签的新数据后,将新数据的每个特征与样本集中数据对 ...
- java基础讲解02-----eclipse快捷方式(2017-04-12 23:47)
ctrl + shift+o 出去多余的引用包 ctrl+i 修改格式
- python hello wlord
入门运行第一个python程序 https://www.python.org/ 官网下载最新python3安装到电脑 安装成功 cmd进入到安装目录 1.在cmd中直接进入到python安装目录 编写 ...
- 【转载】XGBoost调参
General Parameters: Guide the overall functioning Booster Parameters: Guide the individual booster ( ...
- web前端规范
无论是从技术角度还是开发视角,对于web前端开发规范文档都有一定规范,本文就css3和html5的发展前景总结了一系列的web开发文档,仅供大家参考. 规范目的:为提高团队协作效率, 便于后台人员添加 ...
- 智能指针tr1::shared_ptr、boost::shared_ptr使用
对于tr1::shared_ptr在安装vs同一时候会自带安装,可是版本号较低的不存在.而boost作为tr1的实现品,包括 "Algorithms Broken Compiler Work ...
- Mac OSX下Go语言开发环境的搭建与配置--使用InteliJ IDEA 13
折腾了一上午终于把go语言的ide配置好了. 其实GO语言的语法和特性早在去年的时候就学习了一遍.结果后来一直没机会进行开发,结果还是个GO小白.感叹一下,要学好一门编程语言唯一的途径就是多写代码.. ...
- First Objective C
// // main.m // hello-objc // // Created by test5d on 14-9-29. // Copyright (c) 2014年 test5d. All ri ...