瞄一眼CopyOnWriteArrayList(jdk11)
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)的更多相关文章
- 瞄一眼LongAdder(jdk11)
java版本11.0.1,感觉写得太水了,等心情好的时候再重新编辑一下. LongAdder中的核心逻辑主要由java.util.concurrent.atomic.Striped64维护,作为Str ...
- 瞄一眼,带你走进SparkSQL的世界
本文由 网易云发布. 作者:范欣欣(本篇文章仅限知乎内部分享,如需转载,请取得作者同意授权.) 最近想来,大数据相关技术与传统型数据库技术很多都是相互融合.互相借鉴的.传统型数据库强势在于其久经考验 ...
- 后HTML5时代
十二年前,无论多么复杂的布局,在我们神奇的table面前,都不是问题:十年前,阿捷的一本<网站重构>,为我们开启了新的篇章:八年前,我们研究yahoo.com,惊叹它在IE5下都表现得如此 ...
- [深入JUnit] 测试运行的入口
阅读前提 了解JUnit 对JUnit的内部实现有兴趣 不妨看看[深入JUnit] @Before, @After, @Test的秘密] 代码版本: junit 4.12代码搜索工具: http:// ...
- Intellij IDEA 一些不为人知的技巧
Intellij IDEA 一些不为人知的技巧 2016/12/06 | 分类: 基础技术 | 0 条评论 | 标签: IntelliJ 分享到:38 原文出处: khotyn 今天又听了 Jetbr ...
- jq绑定事件的4种方式
jQuery提供了多种绑定事件的方式,每种方式各有其特点,明白了它们之间的异同点,有助于我们在写代码的时候进行正确的选择,从而写出优雅而容易维护的代码.下面我们来看下jQuery中绑定事件的方式都有哪 ...
- [No00007D]2016-面经[上]
面试常见问题: 题一:"请你自我介绍一下" 思路:1.这是面试的必考题目.2.介绍内容要与个人简历相一致.3.表述方式上尽量口语化.4.要切中要害,不谈无关.无用的内容.5.条理要 ...
- [No00006D]下载离线版的github for windows【以Github for Windows 3.0.110.为例】
目录 先上地址后讲原理: 原理: 11个目录的文件怎么一口气下载呢? 最后,把下好的文件批量名,同时将GitHub.exe.manifest也放到软件根目录下(与GitHub.exe同级): 今后的猜 ...
- Linux 小命令
查看 cat 文件名 [查看里面的内容,cate,猫,像猫一样瞄一眼的看] more 文件名 [查看文件,文件太多,一次看不完,用 more 来查看 下一页:空格或 f 下一行:回车 ...
随机推荐
- ajax的dataType有哪些类型?
ajax的dataType有哪些类型? 格式为:dataType:"xxx", •"xml": 返回 XML 文档,可用 jQuery 处理 •"ht ...
- python之golbal/nonlocal
一.关键字 golbal nonlocal 在局部修改全局的变量为什么会报错 count = 0 def func(): count += 1 func() # UnboundLocalError: ...
- Mybatis学习记录(1)
1.Mybatis介绍 Mybatis是apache的一个开源项目iBatis,Mybatis是一个优秀的持久层框架,他对jdbc的操作数据库的过程进行封装,使开发者只需要关注sql本身,不需 ...
- AddDbContext was called with configuration, but the context type 'NewsContext' only declares a parameterless constructor?
问题 An error occurred while starting the application. ArgumentException: AddDbContext was called with ...
- ssh整合思想 Spring分模块开发 crud参数传递 解决HTTP Status 500 - Write operations are not allowed in read-only mode (FlushMode.MANUAL): Turn your Session into FlushMode.COMMIT/AUTO or(增加事务)
在Spring核心配置文件中没有增加事务方法,导致以上问题 Action类UserAction package com.swift.action; import com.opensymphony.xw ...
- Element表单验证(2)
Element表单验证(2) 上篇讲的是async-validator的基本要素,那么,如何使用到Element中以及怎样优雅地使用,就在本篇. 上篇讲到async-validator由3大部分组成 ...
- cena 测评机下载地址
以下是cane的下载地址,现在分享给你们,希望有所帮助 下载地址百度云:https://pan.baidu.com/s/1JBXiVSZy-jhIc0V-F2ESPA 密码:hgtk 点击下载即可. ...
- 【MySql】Mysql ERROR 1067: Invalid default value for ‘date’ 解决
在给一个表添加字段的时候,忽然发现会报一个date类型的字段的默认值错误,郁闷~ 经过排查,原来是MySQL的配置问题,在wamp下,MySQL 5.7里是没有设置 SQL_MODE 的. 1.my. ...
- 16Shell脚本—计划任务服务程序
计划任务服务程序 尽管我们现在已近有了功能彪悍的脚本程序来执行一些批处理工作,但是,如果仍然需要每天凌晨两点敲击键盘回车键来执行这个脚本程序,这简直太痛苦了.为此,我们需要学习如何设置服务器的计划任务 ...
- cols
题目描述 请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径.路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子.如果一条路径经过了矩阵中 ...