CopyOnWriteArrayList是ArrayList线程安全的变体。使用写时复制策略进行修改操作。

与之前版本较明显的区别是,jdk11中用来保护所有设值方法(mutator)的ReentrantLock改为使用关键字synchronized。

文档中也明确表示相比较于ReentrantLock更倾向于使用内置锁(We have a mild preference for builtin monitors over ReentrantLock when either will do.)。

两个都是可重入独占锁,在不涉及到中断、超时等情况时,编码时使用synchronized明显比ReentrantLock优势得多。

CopyOnWriteArrayList的成员变量:

    //锁对象
final transient Object lock = new Object(); //存储数据的数组
private transient volatile Object[] array; final Object[] getArray() {
return array;
} final void setArray(Object[] a) {
array = a;
}

第一个Object对象充当写时复制的锁对象,第二个volatile的array用来存放数据

挑个构造函数看看:

     /**
* 根据Collection迭代器返回的顺序创建包含指定集合元素的列表
*
* @param c 最初保存元素的集合
* @throws NullPointerException 如果指定的集合为null
*/
public CopyOnWriteArrayList(Collection<? extends E> c) {
Object[] es;
if (c.getClass() == CopyOnWriteArrayList.class)
es = ((CopyOnWriteArrayList<?>)c).getArray(); //同类对象直接获取array赋值
else {
es = c.toArray();
// defend against c.toArray (incorrectly) not returning Object[]
// (see e.g. https://bugs.openjdk.java.net/browse/JDK-6260652)
if (es.getClass() != Object[].class)
es = Arrays.copyOf(es, es.length, Object[].class);
}
setArray(es); //array赋值
}

注释中说,L15的条件分支是为了解决Collection.toArray()没有正确地返回为Object[]类型,而是错误地返回为Object类型。这个bug在jdk9已经被修复了。不知道为什么在11.0.2还留着。

jdk中的//单行注释一般都挺有意思的…

读操作和ArrayList没多大差别,所以都是弱一致性的。挑几个写操作看看:

   public void add(int index, E element) {
synchronized (lock) { //获取独占锁
Object[] es = getArray();
int len = es.length;
if (index > len || index < 0) { //越界校验
throw new IndexOutOfBoundsException(outOfBounds(index, len));
}
Object[] newElements;
int numMoved = len - index;
if (numMoved == 0) { //若index=array.length,则新元素添加在末尾
newElements = Arrays.copyOf(es, len + 1);
} else {
newElements = new Object[len + 1]; //创建array副本,调用System.arraycopy()移动index后元素添加新元素于index
System.arraycopy(es, 0, newElements, 0, index);
System.arraycopy(es, index, newElements, index + 1, numMoved);
}
newElements[index] = element;
setArray(newElements); //将修改后的array副本回写给array
}
}
   public E set(int index, E element) {
synchronized (lock) { //获取独占锁
Object[] es = getArray();
E oldValue = elementAt(es, index); //找出index位置的元素
if (oldValue != element) { //如果元素与原先元素不同,则创建array副本。在副本修改后写回array
es = es.clone();
es[index] = element;
setArray(es);
}
return oldValue;
}
}

值得注意的是,之前版本的set方法在上段代码L9多了个分支:

} else {
// Not quite a no-op; ensures volatile write semantics
setArray(elements);
}

注释说了,setArray()是为了保持volatile写的语义,即内存一致性:当存在并发时,将对象放入CopyOnWriteArrayList之前的线程中的操作happen-before随后通过另一线程从CopyOnWriteArrayList中访问或移除该元素的操作。由于jdk11使用synchronized替代了ReentrantLock,也就不需要这一段了。

瞄一眼CopyOnWriteArrayList(jdk11)的更多相关文章

  1. 瞄一眼LongAdder(jdk11)

    java版本11.0.1,感觉写得太水了,等心情好的时候再重新编辑一下. LongAdder中的核心逻辑主要由java.util.concurrent.atomic.Striped64维护,作为Str ...

  2. 瞄一眼,带你走进SparkSQL的世界

    本文由  网易云发布. 作者:范欣欣(本篇文章仅限知乎内部分享,如需转载,请取得作者同意授权.) 最近想来,大数据相关技术与传统型数据库技术很多都是相互融合.互相借鉴的.传统型数据库强势在于其久经考验 ...

  3. 后HTML5时代

    十二年前,无论多么复杂的布局,在我们神奇的table面前,都不是问题:十年前,阿捷的一本<网站重构>,为我们开启了新的篇章:八年前,我们研究yahoo.com,惊叹它在IE5下都表现得如此 ...

  4. [深入JUnit] 测试运行的入口

    阅读前提 了解JUnit 对JUnit的内部实现有兴趣 不妨看看[深入JUnit] @Before, @After, @Test的秘密] 代码版本: junit 4.12代码搜索工具: http:// ...

  5. Intellij IDEA 一些不为人知的技巧

    Intellij IDEA 一些不为人知的技巧 2016/12/06 | 分类: 基础技术 | 0 条评论 | 标签: IntelliJ 分享到:38 原文出处: khotyn 今天又听了 Jetbr ...

  6. jq绑定事件的4种方式

    jQuery提供了多种绑定事件的方式,每种方式各有其特点,明白了它们之间的异同点,有助于我们在写代码的时候进行正确的选择,从而写出优雅而容易维护的代码.下面我们来看下jQuery中绑定事件的方式都有哪 ...

  7. [No00007D]2016-面经[上]

    面试常见问题: 题一:"请你自我介绍一下" 思路:1.这是面试的必考题目.2.介绍内容要与个人简历相一致.3.表述方式上尽量口语化.4.要切中要害,不谈无关.无用的内容.5.条理要 ...

  8. [No00006D]下载离线版的github for windows【以Github for Windows 3.0.110.为例】

    目录 先上地址后讲原理: 原理: 11个目录的文件怎么一口气下载呢? 最后,把下好的文件批量名,同时将GitHub.exe.manifest也放到软件根目录下(与GitHub.exe同级): 今后的猜 ...

  9. Linux 小命令

    查看 cat  文件名     [查看里面的内容,cate,猫,像猫一样瞄一眼的看] more 文件名   [查看文件,文件太多,一次看不完,用 more 来查看 下一页:空格或 f   下一行:回车 ...

随机推荐

  1. C++类和结构体的区别

    C++类和结构体的区别? 结构体默认数据访问控制是public; 类默认数据访问控制是private;

  2. JDK的安装以及环境变量的配置

    一.JDK的安装 1.百度搜索jdk1.8 2.进入网页选择Downloads 3. 选择电脑的版本(x86 32位 x64 64位) 4.下载好后,直接双击即可,一直下一步即可完成安装 二.环境变量 ...

  3. Idea01 Idea2018中集成Tomcat9导致OutPut乱码

    版本和平台 idea2018.3 tomcat9 jdk1.8 windows7 64位 output乱码 经过测试,项目编码格式设置为utf-8,在main方法中输出中文正常. 而iedea集成to ...

  4. 第1节 flume:12、flume的load_balance实现机制

    1.5.flume的负载均衡load balancer 负载均衡是用于解决一台机器(一个进程)无法解决所有请求而产生的一种算法.Load balancing Sink Processor 能够实现 l ...

  5. 科技庄园(背包dp)---对于蒟蒻来说死了一大片的奇题

    题目描述: Life种了一块田,里面种了一些桃树. Life对PFT说:“我给你一定的时间去摘桃,你必须在规定的时间之内回到我面前,否则你摘的桃都要归我吃!” PFT思考了一会,最终答应了! 由于PF ...

  6. Mac配置gdb的一些问题

    1.Unable to find Mach task port for process-id 1527: (os/kern) failure (0x5).   (please check gdb is ...

  7. RAID阵列搭建

    RAID0 2个或2个以上磁盘,称为条带卷,无容错,可提高读写效率,其中一个磁盘损坏,所有文件不可读磁盘大小尽量统一,或者以最小的空间为标准,可用空间=N*min RAID1 2个或2个磁盘以上,称为 ...

  8. matplotlib绘图(一)

    绘制这折现图 导入响应的包 import numpy as npimport pandas as pdfrom pandas import Series,DataFrame%matplotlib in ...

  9. Linux - NodeJS安装

    1> 去NodeJS官网 https://nodejs.org/en/ 或 中文网 http://nodejs.cn/download/ 拷贝相应版本的安装文件,如下图: 2> 执行 wg ...

  10. 常用的windows小工具指令和如何打开自定义的程序

    windows可以通过 开始->运行->输入程序名 或 windows键+R键 两种方式来启动windows中自带的程序或手动安装的程序.下面介绍一些常用的windows工具的指令和如何打 ...