博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
CopyOnWriteArrayList详解
阅读量:5352 次
发布时间:2019-06-15

本文共 3419 字,大约阅读时间需要 11 分钟。

今天在项目中发现有人使用了CopyOnWriteArrayList,但是不明白这个类跟ArrayList有什么区别,于是搜索相关的内容学习一下:

  CopyOnWriteArrayList是ArrayList的一个线程安全的变体,其中所有可变操作(add,set等)都是通过底层数组的进行一次新的复制产生的。

这一般需要很大的开销,但是当遍历操作的数量大大打的超过可变操作的数量时,这种方式更有效。在不能或者不想同步遍历的时候,但又要从并发线程中排出冲突的时候,他很有用。“快照”风格的迭代器方法在创建迭代器时使用了对数组状态的引用。此数组在迭代器的生存期内不会更改,因此不可能发生冲突,并且迭代器保证不会抛出ConCurrentModificationException.创建迭代器以后,迭代器就不会反映列表的添加、移除或者更改。在迭代器上进行元素的更改(remove,set和add)不受支持。这些方法将抛出UnsupportOpreationException。允许使用所有元素包括null.

  内存一致性效果:当存在其他并发Collection的时候,讲对象放入CopyOnWriteArrayList之前的线程中的操作happen-before,随后通过另一线程从CopyOnWriteArayList中访问或移除该元素的操作。

这种情况一般出现在多线程操作时,一个线程堆list进行修改,一个线程对list进行读取时会出现java,util,ConCurrentModificationException错误。

/**   * Project Name:flowbatch-web   * File Name:CopyOnWriteArrayListDemo.java   * Package Name:com.huateng.iccs.flowbatch.runner   * Date:2018年3月1日下午2:10:32   * Copyright (c) 2018, chenzhou1025@126.com All Rights Reserved.   *  */    package com.huateng.iccs.flowbatch.runner;import java.util.ArrayList;import java.util.List;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;/**   * ClassName:CopyOnWriteArrayListDemo 
* Function: TODO ADD FUNCTION.
* Reason: TODO ADD REASON.
* Date: 2018年3月1日 下午2:10:32
* @author Administrator * @version * @since JDK 1.6 * @see */public class CopyOnWriteArrayListDemo { /** * 读线程 * ClassName: ReadTask
* Function: TODO ADD FUNCTION.
* Reason: TODO ADD REASON(可选).
* date: 2018年3月1日 下午2:15:08
* * @author Administrator * @version CopyOnWriteArrayListDemo * @since JDK 1.6 */ private class ReadTask implements Runnable{ private List
list; public ReadTask(List
list) { this.list=list; } @Override public void run() { for (String string : list) { System.out.println(string); } } } private class WriteTask implements Runnable{ private List
list ; private int index; public WriteTask(List
list, int index) { this.index=index; this.list=list; } @Override public void run() { list.remove(index); list.add(index, "write"+index); } } private void run() { int num =10; List
list = new ArrayList
(); for(int i=0;i

  

从结果中可以看出,多线程的情况下报错,如果换成copyonwriteArraylist做容器,这个类和ArrayList最大的区别就是add(E)的时候,容器会自动Copy一份出来然后在尾部add(E)。源码如下

/**     * Appends the specified element to the end of this list.     *     * @param e element to be appended to this list     * @return true (as specified by {
@link Collection#add}) */ 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(); } }

用到了Arrays.copyO方法。这样导致每次操作都不是同一个引用。也就不会出现Java.util.ConcurrentModificationException错误。

换成如下代码

// List<String> list = new ArrayList<String>();

CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<String>();

 

 

 其结果没报错CopyOnWriteArrayList add(E)和remove(int index)都是对新的数组进行修改和新增,所以在多线程操作时不会出现报错,

所以得出的结论:CopyOnWriteArrayList适合使用在读取操作远远大于写操作的场景中,比如缓存。发生修改时做Copy,新老版本分离,保证读的高性能,适用于以读为主的情况

 

注:原文来自https://my.oschina.net/jielucky/blog/167198

 

转载于:https://www.cnblogs.com/GeorgeGong/p/8488437.html

你可能感兴趣的文章
【Qt】Qt Linguist介绍【转】
查看>>
sim usim Uim 区别
查看>>
网页中插入透明Flash的方法和技巧
查看>>
动态内存申请函数选择(realloc、malloc 、alloca、 calloc)
查看>>
获取元素属性get_attribute
查看>>
视觉设计师的进化
查看>>
Python/jquery
查看>>
WPF之Binding
查看>>
【BZOJ】【2132】圈地计划
查看>>
Lua 语言基本语法
查看>>
ARM 的Thumb状态测试
查看>>
windows下读取utf-8文件
查看>>
apache 启动不了的排查方法
查看>>
Java有没有goto?
查看>>
(转)makefile 的用法
查看>>
求不相邻金币相加和的最大值--动态规划1
查看>>
[转][osg]探索未知种族之osg类生物【目录】
查看>>
四十九. Zabbix报警机制 、 Zabbix进阶操作 、 监控案例
查看>>
元类中__new__ 与 __init__的区别--day27
查看>>
占小狼的简书博客
查看>>