博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java 集合 List CopyOnWriteArrayList
阅读量:7108 次
发布时间:2019-06-28

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

hot3.png

参考链接:

Copy-On-Write简称COW,当要修改某个集合时,进行一份集合拷贝,修改新拷贝后的集合,完成后再将新集合指向旧集合。

查看CopyOnWriteArrayList源码

add方法

231342_DLfa_3781047.png

使用final ReentrantLock lock = this.lock;

lock.lock();

在调用add(...)方法前先加锁,保证同一时间只能有一个线程在添加元素。使用Arrays.copyOf(...)方法复制出另一个新的数组,而且新的数组的长度比原来多1,拷贝完成后,将新添加的元素赋值给新数组,最后把新的副本数组赋值给旧的数组,然后在finally中释放锁。

remove方法

删除元素,主要判断是不是删除最后一个元素,如果是的话,直接复制原来数组的length-1,否则先复制数组index前面到新数组,然后再复制index后面的元素到数组中,最后再把新数组赋值给旧数组的引用。

/**     * Removes the element at the specified position in this list.     * Shifts any subsequent elements to the left (subtracts one from their     * indices).  Returns the element that was removed from the list.     *     * @throws IndexOutOfBoundsException {@inheritDoc}     */    public E remove(int index) {        final ReentrantLock lock = this.lock;        lock.lock();        try {            Object[] elements = getArray();            int len = elements.length;            E oldValue = get(elements, index);            int numMoved = len - index - 1;             if (numMoved == 0) // 判断index是不是最后一个,举例如果原来数组总共有3个元素,len 是 3, index 是 2, 则numMoved是0;                setArray(Arrays.copyOf(elements, len - 1));            else {                Object[] newElements = new Object[len - 1]; // 拷贝一个比原来数组长度少一个的数组                System.arraycopy(elements, 0, newElements, 0, index); // 先拷贝index前半部分,                System.arraycopy(elements, index + 1, newElements, index, // 再拷贝index+1后面的部分                                 numMoved);                setArray(newElements); // 最后将新数组的引用赋值给旧数组            }            return oldValue;        } finally {            lock.unlock();        }    }

其次看System.arraycopy(...)方法的源码

191445_yqRR_3781047.png

get方法

231414_jKfX_3781047.png

set方法

231508_eZoo_3781047.png

代码示例:

多线程异常也不是一定会出现的,但使用ArrayList有很大机会会出现并发异常,下面改用CopyOnWriteArrayList可以解决这个问题。如果使用ArrayList没有出现并发异常,建议把线程池改大点。

package com.jerry.entity;import java.util.ArrayList;import java.util.List;import java.util.concurrent.CopyOnWriteArrayList;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class CopyOnWriteListTest {		private static final int THREAD_POOL_MAX_NUM = 10;//	private List
mList = new ArrayList
(); private List
mList = new CopyOnWriteArrayList
(); public static void main(String[] args) { new CopyOnWriteListTest().start(); } private void initData() { this.mList.add("code_99"); this.mList.add("code_98"); this.mList.add("code_97"); } private void start() { initData(); ExecutorService executorService = Executors.newFixedThreadPool(THREAD_POOL_MAX_NUM); for(int i=1; i<=THREAD_POOL_MAX_NUM; i++) { executorService.execute(new ListReader(this.mList)); String codeId = "code_"+i; executorService.execute(new ListWriter(this.mList, codeId)); } executorService.shutdown(); } private class ListReader implements Runnable { private List
rList; public ListReader(List
list) { this.rList = list; } @Override public void run() { if(this.rList != null) { System.out.println("Reader Thread: "+Thread.currentThread().getName()+" --> "+this.rList.toString()); } } } private class ListWriter implements Runnable { private List
wList; private String codeId; public ListWriter(List
list, String codeId) { this.wList = list; this.codeId = codeId; } @Override public void run() { if(this.wList != null) { this.wList.add(codeId); System.out.println("Writer Thread: "+Thread.currentThread().getName()+" --> "+this.wList.toString()); } } }}

CopyOnWriteArrayList的优点和缺点:

优点:解决多线程的并发问题

缺点:

1.内存占用有问题:写时拷贝,内存中会存在两份对象。很明显两个数组同时驻扎在内存中,如果实际应用中,数据比较多,占用内存会比较大,针对这个可以用ConcurrentHashMap来代替。因此,不建议对大对象使用CopyOnWriteArrayList。

ConcurrentHashMap: 

2. 数据的一致性:CopyOnWrite容器只能保证数据的最终一致性,不能保证数据的实时一致性。因此对实时性要求的数据,不建议使用COW。

转载于:https://my.oschina.net/u/3781047/blog/1627519

你可能感兴趣的文章
面试问烂的 Spring AOP 原理、SpringMVC 过程(求求你别问了)
查看>>
第三次作业
查看>>
Spring常用注解
查看>>
Python基本数据类型
查看>>
Extern "C"
查看>>
可用的CSS文字两端对齐
查看>>
Could not get lock /var/lib/dpkg/lock更新问题
查看>>
caffe运行错误: im2col.cu:61] Check failed: error == cudaSuccess (8 vs. 0) invalid device function...
查看>>
人脸检测
查看>>
微信发送红包示例(php)
查看>>
Android-Sqlite数据库的listview分页显示
查看>>
git总结二、关于分支上——好好认识下分支是怎么回事
查看>>
HTML 5 video 视频标签全属性详解
查看>>
最重要的不是你认识多少个人,而是你认识多少种人
查看>>
Java中的get()和set()方法
查看>>
hdoj 2795 Billboard 【线段树 单点更新 + 维护区间最大值】
查看>>
ZOJ 3827 Information Entropy (2014牡丹江区域赛)
查看>>
Cocos2D-X2.2.3学习笔记10(几何图形)
查看>>
SQL优化之OR
查看>>
Linux的启动流程
查看>>