CopyOnWriteArrayList

解决脏读问题;牺牲写的效率,提高读的效率

CopyOnWriteArrayList是一种读写分离的思想体现的ArrayList;

它将读写的操作对象分离开来;

写的过程中,通过复制出一片新的内存,在新的内存中执行完成写操作,再赋值回去,完成写操作;

在写的过程中,可以进行并发的读,因为操作的并不是同一片内存;

这样就避免了java.util.ConcurrentModificationException并发修改异常了;

下面一步步来看一下源码,怎么实现的?

只分析了部分常用的API的源码:读取get和写入add

构造器

直接看源码,不是很复杂;

public class CopyOnWriteArrayList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable { final transient ReentrantLock lock = new ReentrantLock();
private transient volatile Object[] array; //数据都会存储在这个array中
// 提供set,get方法
final Object[] getArray() {
return array;
}
final void setArray(Object[] a) {
array = a;
}
// ①无参构造器
public CopyOnWriteArrayList() {
setArray(new Object[0]); // 初始化一个长度0的array
}
// ②将一个Collection转化为CopyOnWriteArrayList
public CopyOnWriteArrayList(Collection<? extends E> c) {
Object[] elements;
// 此Collection就是CopyOnWriteArrayList,直接赋值
if (c.getClass() == CopyOnWriteArrayList.class)
elements = ((CopyOnWriteArrayList<?>)c).getArray();
else {
// 其余都转化为Object数组赋值
elements = c.toArray();
if (elements.getClass() != Object[].class)
elements = Arrays.copyOf(elements, elements.length, Object[].class);
}
setArray(elements);
}
// ③直接传入一个泛型数组
public CopyOnWriteArrayList(E[] toCopyIn) {
setArray(Arrays.copyOf(toCopyIn, toCopyIn.length, Object[].class));
}

add

添加方法,此类的重点方法:即:写操作的实现;

CopyOnWrite容器,即写时复制的容器;

添加元素的时候,并不直接添加,而是先将array复制一份给 Object[ ] newElements,且newElements长度加1,表示要添加一个元素;

添加的操作,都是针对newElements进行的,不对原array进行操作;

这样就将,写操作的内存,与读操作的内存分离开来,写的过程不会影响并发读取;

源码:

// 添加方法
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
newElements[len] = e;// 添加元素
setArray(newElements);// 将添加完成的newElements赋值给原array
return true;
} finally {
lock.unlock();
}
}
final Object[] getArray() {
return array;
}
final void setArray(Object[] a) {
array = a;
}

get

读取操作,没有做任何的同步措施;

array并不会发生修改,只会在写操作后,直接替换,不存在数据安全问题;

public E get(int index) {
return get(getArray(), index);
}
private E get(Object[] a, int index) {
return (E) a[index];
}
final Object[] getArray() {
return array;
}

【JUC】8.CopyOnWriteArrayList源码分析的更多相关文章

  1. CopyOnWriteArrayList 源码分析 基于jdk1.8

    CopyOnWriteArrayList  源码分析: 1:成员属性: final transient ReentrantLock lock = new ReentrantLock();  //内部是 ...

  2. JUC之CountDownLatch源码分析

    CountDownLatch是AbstractQueuedSynchronizer中共享锁模式的一个的实现,是一个同步工具类,用来协调多个线程之间的同步.CountDownLatch能够使一个或多个线 ...

  3. CopyOnWriteArrayList源码分析

    基于jdk1.7源码 一.无锁容器 CopyOnWriteArrayList是JDK5中添加的新的容器,除此之外,还有CopyOnWriteArraySet.ConcurrentHahshMap和Co ...

  4. JUC AQS ReentrantLock源码分析

    警告⚠️:本文耗时很长,先做好心理准备,建议PC端浏览器浏览效果更佳. Java的内置锁一直都是备受争议的,在JDK1.6之前,synchronized这个重量级锁其性能一直都是较为低下,虽然在1.6 ...

  5. Java并发编程笔记之CopyOnWriteArrayList源码分析

    并发包中并发List只有CopyOnWriteArrayList这一个,CopyOnWriteArrayList是一个线程安全的ArrayList,对其进行修改操作和元素迭代操作都是在底层创建一个拷贝 ...

  6. JUC之ReentrantLock源码分析

    ReentrantLock:实现了Lock接口,是一个可重入锁,并且支持线程公平竞争和非公平竞争两种模式,默认情况下是非公平模式.ReentrantLock算是synchronized的补充和替代方案 ...

  7. 死磕 java集合之CopyOnWriteArrayList源码分析

    欢迎关注我的公众号"彤哥读源码",查看更多源码系列文章, 与彤哥一起畅游源码的海洋. 简介 CopyOnWriteArrayList是ArrayList的线程安全版本,内部也是通过 ...

  8. 多线程十之CopyOnWriteArrayList源码分析

    目录 简介 类结构 源码解析 构造方法 add(E e) add(int index, E element) get(int index) remove(int index) 迭代器Iterator遍 ...

  9. CopyOnWriteArrayList 源码分析

    CopyOnWriteArrayList CopyOnWriteArrayList 能解决什么问题?什么时候使用 CopyOnWriteArrayList? 1)CopyOnWriteArrayLis ...

随机推荐

  1. Flutter中通过普通的点击事件修改TextFormField的值

    import 'package:flutter/material.dart'; import 'package:zhongfa_apps/widget/public/PublicWidget.dart ...

  2. 【翻译】Flink Table Api & SQL —Streaming 概念 ——时间属性

    本文翻译自官网: Time Attributes   https://ci.apache.org/projects/flink/flink-docs-release-1.9/dev/table/str ...

  3. EasyDSS高性能RTMP、HLS(m3u8)、FLV、RTSP流媒体服务器运行遇到getpwnam(_xxxxx_)错误的解决办法

    EasyDSS RTMP流媒体服务器是什么? EasyDarwin如何支持点播和RTMP/HLS直播?EasyDSS! getpwnam("xxxxx") 近期有EasyDSS流媒 ...

  4. 【视频开发】【CUDA开发】FFMPEG硬件加速-nvidia方案

    1.目标 <1>显卡性能参数: <2>方案可行性: 2.平台信息 2.1.查看当前显卡信息 命令:  lspci |grep VGA  信息:  01:00.0 VGA com ...

  5. Jenkins插件、war下载地址

    1.jenkins的war包下载地址 地址:http://mirrors.jenkins-ci.org/,打开链接后,表格有war列,Releases行是短期更新包.LTS是长期更新包.一般选择Rel ...

  6. 在ensp上的mstp基础配置

    为什么需要mstp? 因为stp中存在阻塞端口,阻塞后不承载流量,造成了带宽浪费 实验模拟 实验拓扑 相关参数 首先我们在交换机上创建vlan 10,20 设置端口 默认是运行mstp服务看一下

  7. qmake, makefile, make是什么东东,makefile简介!

    qmake是一个协助简化跨平台开发的构建过程 的工具,Qt附带的工具之一 .qmake能够自动生成Makefile.Microsoft Visual Studio 专案文件 和 xcode 专案文件. ...

  8. Java字符串无意识的递归

    Java中的每个类基本上都继承自Object,标准容器类自然也不例外.因此容器类都有toString()方法,并且重写了该方法,使得它生成的String结果能够表达容器本身,以及容器所包含的对象.例如 ...

  9. TemplateDoesNotExist

    路径问题,可能是没有配置这一行:

  10. 关于st表

    #include<cstdio> #include<iostream> #include<cmath> #include<cctype> #includ ...