CopyOnWriteArrayList与Collections.synchronizedList的性能对比
1 ArrayList
ArrayList是非线性安全,此类的 iterator 和 listIterator 方法返回的迭代器是快速失败的:在创建迭代器之后,除非通过迭代器自身的 remove 或 add 方法从结构上对列表进行修改,否则在任何时间以任何方式对列表进行修改,迭代器都会抛出 ConcurrentModificationException。即在一方在便利列表,而另一方在修改列表时,会报ConcurrentModificationException错误。而这不是唯一的并发时容易发生的错误,在多线程进行插入操作时,由于没有进行同步操作,容易丢失数据。
- public boolean add(E e) {
- ensureCapacity(size + 1); // Increments modCount!!
- elementData[size++] = e;//使用了size++操作,会产生多线程数据丢失问题。
- return true;
- }
因此,在开发过程当中,ArrayList并不适用于多线程的操作。
2 Vector
3 Collections.synchronizedList & CopyOnWriteArrayList
3.1 Collections.synchronizedList
- public static <T> List<T> synchronizedList(List<T> list) {
- return (list instanceof RandomAccess ?
- new SynchronizedRandomAccessList<T>(list) :
- new SynchronizedList<T>(list));//根据不同的list类型最终实现不同的包装类。
- }
其中,SynchronizedList对部分操作加上了synchronized关键字以保证线程安全。但其iterator()操作还不是线程安全的。部分SynchronizedList的代码如下:
- public E get(int index) {
- synchronized(mutex) {return list.get(index);}
- }
- public E set(int index, E element) {
- synchronized(mutex) {return list.set(index, element);}
- }
- public void add(int index, E element) {
- synchronized(mutex) {list.add(index, element);}
- }
- public ListIterator<E> listIterator() {
- return list.listIterator(); // Must be manually synched by user 需要用户保证同步,否则仍然可能抛出ConcurrentModificationException
- }
- public ListIterator<E> listIterator(int index) {
- return list.listIterator(index); // Must be manually synched by user <span style="font-family: Arial, Helvetica, sans-serif;">需要用户保证同步,否则仍然可能抛出ConcurrentModificationException</span>
- }
3.2 CopyOnWriteArrayList
- /** The lock protecting all mutators */
- transient final ReentrantLock lock = new ReentrantLock();
- /** The array, accessed only via getArray/setArray. */
- private volatile transient Object[] array;//保证了线程的可见性
- public boolean add(E e) {
- final ReentrantLock lock = this.lock;//ReentrantLock 保证了线程的可见性和顺序性,即保证了多线程安全。
- lock.lock();
- try {
- Object[] elements = getArray();
- int len = elements.length;
- Object[] newElements = Arrays.copyOf(elements, len + 1);//在原先数组基础之上新建长度+1的数组,并将原先数组当中的内容拷贝到新数组当中。
- newElements[len] = e;//设值
- setArray(newElements);//对新数组进行赋值
- return true;
- } finally {
- lock.unlock();
- }
- }
其读操作代码如下:
- public E get(int index) {
- return (E)(getArray()[index]);
- }
其没有加任何同步关键字,根据以上写操作的代码可知,其每次写操作都会进行一次数组复制操作,然后对新复制的数组进行些操作,不可能存在在同时又读写操作在同一个数组上(不是同一个对象),而读操作并没有对数组修改,不会产生线程安全问题。Java中两个不同的引用指向同一个对象,当第一个引用指向另外一个对象时,第二个引用还将保持原来的对象。
其中setArray()操作仅仅是对array进行引用赋值。Java中“=”操作只是将引用和某个对象关联,假如同时有一个线程将引用指向另外一个对象,一个线程获取这个引用指向的对象,那么他们之间不会发生ConcurrentModificationException,他们是在虚拟机层面阻塞的,而且速度非常快,是一个原子操作,几乎不需要CPU时间。
3.3 Collections.synchronizedList & CopyOnWriteArrayList在读写操作上的差距
- package com.yang.test;
- import org.junit.Test;
- import java.util.*;
- import java.util.concurrent.*;
- /**
- * Created with IntelliJ IDEA.
- * User: yangzl2008
- * Date: 14-9-18
- * Time: 下午8:36
- * To change this template use File | Settings | File Templates.
- */
- public class Test02 {
- private int NUM = 10000;
- private int THREAD_COUNT = 16;
- @Test
- public void testAdd() throws Exception {
- List<Integer> list1 = new CopyOnWriteArrayList<Integer>();
- List<Integer> list2 = Collections.synchronizedList(new ArrayList<Integer>());
- Vector<Integer> v = new Vector<Integer>();
- CountDownLatch add_countDownLatch = new CountDownLatch(THREAD_COUNT);
- ExecutorService executor = Executors.newFixedThreadPool(THREAD_COUNT);
- int add_copyCostTime = 0;
- int add_synchCostTime = 0;
- for (int i = 0; i < THREAD_COUNT; i++) {
- add_copyCostTime += executor.submit(new AddTestTask(list1, add_countDownLatch)).get();
- }
- System.out.println("CopyOnWriteArrayList add method cost time is " + add_copyCostTime);
- for (int i = 0; i < THREAD_COUNT; i++) {
- add_synchCostTime += executor.submit(new AddTestTask(list2, add_countDownLatch)).get();
- }
- System.out.println("Collections.synchronizedList add method cost time is " + add_synchCostTime);
- }
- @Test
- public void testGet() throws Exception {
- List<Integer> list = initList();
- List<Integer> list1 = new CopyOnWriteArrayList<Integer>(list);
- List<Integer> list2 = Collections.synchronizedList(list);
- int get_copyCostTime = 0;
- int get_synchCostTime = 0;
- ExecutorService executor = Executors.newFixedThreadPool(THREAD_COUNT);
- CountDownLatch get_countDownLatch = new CountDownLatch(THREAD_COUNT);
- for (int i = 0; i < THREAD_COUNT; i++) {
- get_copyCostTime += executor.submit(new GetTestTask(list1, get_countDownLatch)).get();
- }
- System.out.println("CopyOnWriteArrayList add method cost time is " + get_copyCostTime);
- for (int i = 0; i < THREAD_COUNT; i++) {
- get_synchCostTime += executor.submit(new GetTestTask(list2, get_countDownLatch)).get();
- }
- System.out.println("Collections.synchronizedList add method cost time is " + get_synchCostTime);
- }
- private List<Integer> initList() {
- List<Integer> list = new ArrayList<Integer>();
- int num = new Random().nextInt(1000);
- for (int i = 0; i < NUM; i++) {
- list.add(num);
- }
- return list;
- }
- class AddTestTask implements Callable<Integer> {
- List<Integer> list;
- CountDownLatch countDownLatch;
- AddTestTask(List<Integer> list, CountDownLatch countDownLatch) {
- this.list = list;
- this.countDownLatch = countDownLatch;
- }
- @Override
- public Integer call() throws Exception {
- int num = new Random().nextInt(1000);
- long start = System.currentTimeMillis();
- for (int i = 0; i < NUM; i++) {
- list.add(num);
- }
- long end = System.currentTimeMillis();
- countDownLatch.countDown();
- return (int) (end - start);
- }
- }
- class GetTestTask implements Callable<Integer> {
- List<Integer> list;
- CountDownLatch countDownLatch;
- GetTestTask(List<Integer> list, CountDownLatch countDownLatch) {
- this.list = list;
- this.countDownLatch = countDownLatch;
- }
- @Override
- public Integer call() throws Exception {
- int pos = new Random().nextInt(NUM);
- long start = System.currentTimeMillis();
- for (int i = 0; i < NUM; i++) {
- list.get(pos);
- }
- long end = System.currentTimeMillis();
- countDownLatch.countDown();
- return (int) (end - start);
- }
- }
- }
操作结果:
| 写操作 | 读操作 | |||
| CopyOnWriteArrayList | Collections. synchronizedList |
CopyOnWriteArrayList | Collections. synchronizedList |
|
| 2 | 567 | 2 | 1 | 1 |
| 4 | 3088 | 3 | 2 | 2 |
| 8 | 25975 | 28 | 2 | 3 |
| 16 | 295936 | 44 | 2 | 6 |
| 32 | - | - | 3 | 8 |
| 64 | - | - | 7 | 21 |
| 128 | - | - | 9 | 38 |
写操作:在线程数目增加时CopyOnWriteArrayList的写操作性能下降非常严重,而Collections.synchronizedList虽然有性能的降低,但下降并不明显。
4 结论
CopyOnWriteArrayList与Collections.synchronizedList的性能对比的更多相关文章
- CopyOnWriteArrayList与Collections.synchronizedList的性能对比(转)
列表实现有ArrayList.Vector.CopyOnWriteArrayList.Collections.synchronizedList(list)四种方式. 1 ArrayList Array ...
- CopyOnWriteArrayList&Collections.synchronizedList()
1.ArrayList ArrayList是非线性安全,此类的 iterator() 和 listIterator() 方法返回的迭代器是快速失败的:在创建迭代器之后,除非通过迭代器自身的 remov ...
- Collections.synchronizedList 、CopyOnWriteArrayList、Vector介绍、源码浅析与性能对比
## ArrayList线程安全问题 众所周知,`ArrayList`不是线程安全的,在并发场景使用`ArrayList`可能会导致add内容为null,迭代时并发修改list内容抛`Concurre ...
- Collections.synchronizedList与CopyOnWriteArrayList比较
1.单线程方式 2.多线程版本,不安全的 ArrayList 3.多线程版本,线程安全,CopyOnWriteArrayList()方式 4.多线程版本,线程安全,Collections.synchr ...
- ConcurrentHashMap和 CopyOnWriteArrayList提供线程安全性和可伸缩性 以及 同步的集合类 Hashtable 和 Vector Collections.synchronizedMap 和 Collections.synchronizedList 区别缺点
ConcurrentHashMap和 CopyOnWriteArrayList提供线程安全性和可伸缩性 DougLea的 util.concurrent 包除了包含许多其他有用的并发构造块之外,还包含 ...
- StringBuilder和string.Format性能对比
本文由博主(YinaPan)原创,转载请注明出处:http://www.cnblogs.com/YinaPan/p/sbformat.html StringBuilder的性能优于string.For ...
- 求斐波那契数列第n位的几种实现方式及性能对比(c#语言)
在每一种编程语言里,斐波那契数列的计算方式都是一个经典的话题.它可能有很多种计算方式,例如:递归.迭代.数学公式.哪种算法最容易理解,哪种算法是性能最好的呢? 这里给大家分享一下我对它的研究和总结:下 ...
- Collections.synchronizedList使用
1.SynchronizedList类具体代码: static class SynchronizedList<E> extends SynchronizedCollection<E& ...
- WPF DataGrid与ListView性能对比与场景选择
开门见山的说 性能对比: 在Demo中,DataGrid与ListView默认开启虚拟化(可以理解为动态渲染,类似懒加载只渲染屏幕可以看见的地方) DataGrid渲染10列50行随机字符280ms ...
随机推荐
- Windows 7中,用Visual Studio开发WPF应用程序,实现从Windows Explorer中拖拽文件到应用程序,始终显示“无法拖放”符号问题解决方案
Are you running your application or Visual Studio that hosts the app under administrative privilege? ...
- jdbc-connect-oracle12c-pdb/cdb(jdbc连接oracle12c的pdb和cdb)
1 本文简介: 通过特意引发问题,聚焦问题,解决问题,并循序渐进 最后总结jdbc连接oracle12c中cdb和pdb的条件. 软件环境:Redhat7.1+orcacle12c 2 ...
- ios fixed属性bug解决方法
在内容层外面包一个div 加上样式:position:fixed;top:0px; bottom:50px;overflow:scroll; 就可以完美解决
- 0基础学习ios开发笔记第二天
C语言的基本结构 c语言的入口函数是main函数. main函数的返回值行业标准是int return 数字:返回值 每条语句最后以分号结尾 注释:行注释.块注释 int main(void) { / ...
- MarkDown 格式生产类型
-- 不默认换行, 真的结束, 包括格式设定,记得空一行. -- 学习参考地址如下, 讲的不好, 太复杂, 不适合新手. 有好读的更好. ** 但是江湖规矩 还是引用下吧 这是地址(http://wo ...
- windows server 2003 取消登录Ctrl+Alt+delete
安装Windows Server 2003操作系统的, 在console登录默认要先按下Ctrl+Alt+Delete组合键然后才弹出登录对话框 要取消这个限制的方法是: 点击 “开始-->运行 ...
- 《程序员的思维修炼》摘抄start:2014年9月27日19:27:07
程序员的思维修炼:摘抄:考虑到社会中各个相关团体的复杂交互影响和社会的持续变化,在我看来当前最重要的两项技能就是: ▪沟通能力: ▪学习和思考能力.软件行业正在逐步提高沟通能力.特别是敏捷方法(见注解 ...
- ZOJ 1091 (HDU 1372) Knight Moves(BFS)
Knight Moves Time Limit: 2 Seconds Memory Limit: 65536 KB A friend of you is doing research on ...
- 处理safari缓存的办法
window.onpageshow = function(event) { if (event.persisted) { alert("From bac ...
- ssh命令:隧道代理+本地端口转发+远程端口转发
0.前言 nc是一个在网络连接两端的好工具,同时也是也个临时的端口转发的好工具.(永久的端口转发用什么?用iptables) ssh也是这方面的好工具,好处是加密可靠可复用在一端操作即可,代价 ...