CopyOnWriteArrayList 源码阅读与分析

CopyOnWriteArrayList 源码阅读与分析

CopyOnWriteArrayList是并发包下的一个线程安全、可以实现高并发的ArrayList

首先来看看它的构造方法:

final void setArray(Object[] a) {

array = a;

}

/**

* Creates an empty list.

*/

public CopyOnWriteArrayList() {

setArray(new Object[0]);

}

可以看到,它和ArrayList有一定的不同,它是创建一个大小为 0 的数组。ArrayList是一个空数组。

下面来看看它的add(E) 方法,进一步了解它的实现原理

顾名思义,它的名字叫CopyOnWriteArrayList(),也就是在进行写操作时,如add,remove时,会进行复制操作,即创建一个新的比当前数长度大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();

}

}

add 方法并没有使用 synchronized 关键字来实现互斥,而是通过使用ReentrantLock 来进行加锁操作。可以看到,它的实现比较简单,首先加锁,然后创建一个比目前数组长度大1的新数组,再把旧数组中的值复制到新的数组中去。然后再调用setArray方法改变引用,完成add的操作,结束以后,再释放锁。

之所以再每次的修改数组操作(add/remove等)之后,会新建一个数组,修改完毕之后,再将原来的引用指向新的数组。是为了保证数组被一个线程遍历时,没有其他线程对数组进行修改。所以也就不会抛出ArrayList并发情况下出现的ConcurrentModificationException错误。

下面再来看看get(int) 方法

先来看看代码的实现:

public E get(int index) {

return get(getArray(), index);

}

@SuppressWarnings("unchecked")

private E get(Object[] a, int index) {

return (E) a[index];

}

可以看到,非常简单,直接获取当前数组对应的位置的元素,但是由于方法没有进行任何的加锁操作,所以可能会出现读到脏数据的现象,这样可以有比较高的性能,所以在修改少,读取多的场景下。它开始很好的选择。

再来看看remove(E) 方法

和 add 方法一样,此方法也通过ReetrantLock 来保证其线程安全。

首先判断要删除的元素是不是最后一个元素:

Object[] elements = getArray();

int len = elements.length;

E oldValue = get(elements, index);

int numMoved = len - index - 1;

如果是最后一个元素,就把原来的数组除去最后一个元素都 复制到新的数组中,再改变引用。如下所示:

if(numMoved == 0)

setArray(Arrays.copyOf(elements,len - 1));

如果不是最后一个元素,就进行两次复制,先把原数组从0到index-1的数据复制到新的数组,再把index+1到最后一个元素复制到新的数组中,最后再改变引用。完成这些以后,就完成了删除的操作。

可以看到CopyOnWriteArrayList没有像ArrayList一样的动态扩容机制,而是再每次对数组修改时都会新建一个新的数组,为了避免ConcurrentModificationException异常,但是这样也会对性能有一定的影响。而且它并没有对读操作进行任何的线程安全的操作,所以可能会出现读到脏数据的情况。所以当写操作比较多时,使用CopyOnWriteArrayList个人感觉不是好的选择。

时间: 2024-10-13 23:00:47

CopyOnWriteArrayList 源码阅读与分析的相关文章

ArrayBlockingQueue 源码阅读与分析

ArrayBlockingQueue 源码阅读与分析 通过这个类的名字,可以知道ArrayBlockingQueue是一个底层使用数组实现,具有队列特点的先进先出以及线程安全的一个集合类,他还可以实现指定时间的阻塞读写,也就是可以解决生产者消费者问题的阻塞队列. 首先来看一下它的构造方法: public ArrayBlockingQueue(int capacity) { this(capacity, false); } public ArrayBlockingQueue(int capacit

HTTP请求库——axios源码阅读与分析

概述 在前端开发过程中,我们经常会遇到需要发送异步请求的情况.而使用一个功能齐全,接口完善的HTTP请求库,能够在很大程度上减少我们的开发成本,提高我们的开发效率. axios是一个在近些年来非常火的一个HTTP请求库,目前在GitHub中已经拥有了超过40K的star,受到了各位大佬的推荐. 今天,我们就来看下,axios到底是如何设计的,其中又有哪些值得我们学习的地方.我在写这边文章时,axios的版本为0.18.0.我们就以这个版本的代码为例,来进行具体的源码阅读和分析.当前axios所有

源码阅读与分析一:利用eclipse查看ssh等源码

要阅读开源框架代码,阅读class文件,我们一般有两种方法 1.利用maven进行相关操作 2.下载jar包的源码包进行导入阅读 这里我采用的是第二种 具体步骤如下: 一:这里如果我们要阅读struts源码,首先到官方下载,这里推荐下载all包,就是包含docs,src,lib的包,当然你也可以只下载lib和src包,lib包为我们的jar包,就是平常需要导入项目的,src包为jar包的源码包,里面包含所有jar包的.java源文件,docs则是我们的文档,里面包含struts的使用说明文档 首

CopyOnWriteArrayList源码阅读

java.util.concurrent包中定义常见集合类对应的并发集合类,用于高效处理并发场景,其中CopyOnWriteArrayList对应就是ArrayList.顾名思义CopyOnWrite,写时拷贝,这里写包括对集合类的修改操作,都会创建一个副本. CopyOnWriteArrayList的实现 类的定义 public class CopyOnWriteArrayList<E> implements List<E>, RandomAccess, Cloneable, j

《java.util.concurrent 包源码阅读》08 CopyOnWriteArrayList和CopyOnWriteArraySet

CopyOnWriteArrayList和CopyOnWriteArraySet从数据结构类型上来说是类似的,都是用数组实现的保存一组数据的数据结构,区别也简单就是List和set的区别.因此这里就先讨论CopyOnWriteArrayList,然后再说CopyOnWriteArraySet. 这里重点关注的是CopyOnWrite,从字面上很容易理解,每当写操作的时候复制存储数据的数组,把拷贝上修改完再覆盖原先的数组.那么这样的数据结构适用的情况必然是读操作占绝大多数(很少进行写操作),且数据

JDK源码阅读(一):Object源码分析

最近经过某大佬的建议准备阅读一下JDK的源码来提升一下自己 所以开始写JDK源码分析的文章 阅读JDK版本为1.8 目录 Object结构图 构造器 equals 方法 getClass 方法 hashCode 方法 toString 方法 finalize 方法 registerNatives 方法 1. Object结构图 2. 类构造器 ??类构造器是创建Java对象的方法之一.一般我们都使用new关键字来进行实例,还可以在构造器中进行相应的初始化操作. ??在一个Java类中必须存在一个

《java.util.concurrent 包源码阅读》 结束语

<java.util.concurrent 包源码阅读>系列文章已经全部写完了.开始的几篇文章是根据自己的读书笔记整理出来的(当时只阅读了部分的源代码),后面的大部分都是一边读源代码代码,一边写文章. 由于水平有限,在阅读源代码的时候,分析得也比较浅显,也有很多地方自己也没有研究明白,文章有的地方显得语焉不详,只能请各位多多见谅了. 后面会继续写一些关于Java并发编程的文章,希望各位多多指教. 这里整理了一个简单的目录,包含了本系列所有文章的链接: <java.util.concurr

CI源码阅读

CodeIgniter源码分析 http://calixwu.com/2014/11/codeigniter-yuanmafenxi.html CI框架源码阅读笔记 http://www.cnblogs.com/ohmygirl/p/4052686.html

Netty源码阅读(一) ServerBootstrap启动

Netty源码阅读(一) ServerBootstrap启动 转自我的Github Netty是由JBOSS提供的一个java开源框架.Netty提供异步的.事件驱动的网络应用程序框架和工具,用以快速开发高性能.高可靠性的网络服务器和客户端程序.本文讲会对Netty服务启动的过程进行分析,主要关注启动的调用过程,从这里面进一步理解Netty的线程模型,以及Reactor模式. 这是我画的一个Netty启动过程中使用到的主要的类的概要类图,当然是用到的类比这个多得多,而且我也忽略了各个类的继承关系