来源

看java并发编程之美P110提到:

如果指定位置的元素值与新值一样,则为了保证volatile语义,还是需要重新设置array,虽然array的内容并没有改变。

这里只是提到保证volatile语义,但是解释得不详细。

可以看下这篇文章 「源码分析」CopyOnWriteArrayList 中的隐藏的知识,你 Get 了吗? | 未读代码

Copy过来:

修改元素和新增元素的思想是一致的,通过 ReentrantLock 锁保证线程安全性,实现代码也比较简单,本来不准备写进来的,但是在看源码时发现一个非常有意思的地方,看下面的代码。

public E set(int index, E element) {final ReentrantLock lock = this.lock;lock.lock(); //加锁try {Object[] elements = getArray(); // 获取老数组E oldValue = get(elements, index); // 获取指定位置元素if (oldValue != element) { // 新老元素是否相等,不相等int len = elements.length;Object[] newElements = Arrays.copyOf(elements, len); // 复制老数组newElements[index] = element; // 指定位置赋新值setArray(newElements); // 替换掉老数组} else {// Not quite a no-op; ensures volatile write semanticssetArray(elements);  // 有意思的地方来了}return oldValue;} finally {lock.unlock();}
}

通过源码可以看到在修改元素前会先比较修改前后的值是否相等,而在相等的情况下,依旧 setArray(elements); 这就很奇妙了,到底是为什么呢?想了解其中的原因需要了解下 volatile 的特殊作用,通过下面这个代码例子说明。

// initial conditions
int nonVolatileField = 0;
CopyOnWriteArrayList<String> list = /* a single String */// Thread 1
nonVolatileField = 1;                 // (1)
list.set(0, "x");                     // (2)// Thread 2
String s = list.get(0);               // (3)
if (s == "x") {int localVar = nonVolatileField;  // (4)
}
// 例子来自:https://stackoverflow.com/questions/28772539/why-setarray-method-call-required-in-copyonwritearraylist

要想理解例子中的特殊之处,首先你要知道 volatile 可以防止指令重排,其次要了解 happens-before 机制。说简单点就是它们可以保证代码的执行前后顺序

比如上面例子中的代码,1 会在 2 之前执行,3 会在 4 之前执行,这都没有疑问。还有一条是 volatile 修饰的属性写会在读之前执行,所以 2 会在 3 之前执行。(CopyOnWriteArrayList 的volatile修饰的array属性)。

CopyOnWriteArrayList 的内部维护着一个使用 volatile 修饰的数组,用来存放元素数据。

/** The array, accessed only via getArray/setArray. */
private transient volatile Object[] array;

而执行顺序还存在传递性。所以最终 1 会在 4 之前执行。这样 4 获取到的值就是步骤 1 为 nonVolatileField 赋的值。如果 CopyOnWriteArrayList 中的 set 方法内没有为相同的值进行 setArray,那么上面说的这些就都不存在了

也就是说,如果没有这行代码,在相等的情况下,set方法就不会对volatile 修饰的array属性操作,那么4可能就会出现在1前面,也就是说 4 可能无法获取到步骤 1 为nonVolatileField 赋的值


事实上:

如果在相等的情况下,没有setArray(elements);的话,也可以通过在外部用volatile修饰变量,在上例中就是volatile nonVolatileField,同样可以防止指定重排。


引用 CopyOnWriteArrayList set方法中的 Not quite a no-op; ensures volatile write semantics_一颗小小的石头.的博客-CSDN博客 中一句话

这不是为了保证CopyOnWriteArrayList本身的可见性

而是保证外部的非volatile变量遵循happen−before原则

Not quite a no-op; ensures volatile write semantics相关推荐

  1. // Not quite a no-op; ensures volatile write semantics怎么理解

    // Not quite a no-op; ensures volatile write semantics怎么理解 只解释一句 自学源码,看到CopyOnWriteArrayList 类里面有这样一 ...

  2. 【面试专栏】第三篇:Java基础:集合篇-List、Queue

    面试中问完基础基本上就是考集合,因为集合的使用在业务开发中经常使用,而且集合的数据结构也是算法的基础,所以你对集合的掌握深度可能决定你有没有接着面的资格 List & Queue 实现类 Li ...

  3. 如何实现ArrayList的线程安全

    ArrayList用的太多了,几乎所有人都知道它是线程不安全的,但实际使用中,我们的多线程实现,普遍都是基于一些同步方法或者锁,很多场景其实并不需要关注ArrayList本身的线程安全.网上可以找到三 ...

  4. [Professor麦]并发编程就该这么学(长文预警)

    二轮复盘并发编程!!文末有一些我学习并发编程的感受,不知道怎么入手的可以看看,正所谓传道授业解惑也,传递怎么学比知识更重要!欢迎在评论区和我交流讨论 什么是线程安全 当多个线程同时访问一个对象时,如果 ...

  5. 尚硅谷大厂面试题第二季(上)

    尚硅谷大厂面试题第二季(上) 1. volatile关键字理解 volatile是Java提供的轻量级的同步机制,主要有三个特性: 保证内存可见性 不保证原子性 禁止指令重排序 1.1 保证内存可见性 ...

  6. Java CopyOnWriteArrayList

    Copy-On-Write简称COW,是一种用于程序设计中的优化策略.其基本思路是,从一开始大家都在共享同一个内容,当某个人想要修改这个内容的时候,才会真正把内容Copy出去形成一个新的内容然后再改, ...

  7. CopyOnWriteArrayList简介

    CopyOnWriteArrayList,写数组的拷贝,支持高效率并发且是线程安全的,读操作无锁的ArrayList.所有可变操作都是通过对底层数组进行一次新的复制来实现. CopyOnWriteAr ...

  8. happens-before俗解

    学习Java并发,到后面总会接触到happens-before偏序关系.初接触玩意儿简直就是不知所云,下面是经过一段时间折腾后个人对此的一点浅薄理解,希望对初接触的人有帮助.如有不正确之处,欢迎指正. ...

  9. java并发编程之美-阅读记录5

    java并发包中的并发List 5.1CopeOnWriteArrayList 并发包中的并发List只有CopyOnWriteArrayList,该类是一个线程安全的arraylist,对其进行的修 ...

最新文章

  1. Flutter开发之JSON及序列化(29)
  2. 端午郑州行·世纪欢乐园
  3. linux 本地socket 简介
  4. python怎么导入时间-Python的import导入与时间
  5. Android自动化测试工具Appium环境搭建
  6. 01-NVIDIA Jetson TX2开箱上电显示界面
  7. JSON字符串与JSON对象的区别
  8. python standardscaler_教你用python一步步解决“维度灾难”
  9. java中静态代码块的用法 static用法详解
  10. 让学生员工上夜班加班,供应商“惹怒”苹果:暂停与其新业务合作
  11. Hadoop笔记整理(三):Zookeeper
  12. Google陆续收购技能机器人技术公司——智能机器人未来是否会发热?
  13. 后缀数组三·重复旋律3
  14. java线程wait_Java 并发编程:线程间的协作(wait/notify/sleep/yield/join)
  15. 修改Win7启动顺序和启动菜单名称
  16. 如何留住你的员工——员工流失分析
  17. ES系列:字段类型不对时,如何保存文档到索引
  18. aircrack-ng/airdrop-ng
  19. nfc和红外线的区别_比较NFC支付、蓝牙支付、红外线支付技术的优缺点
  20. 温商机器人企业_16家温商企业上榜“中国民企500强” 青山控股领衔

热门文章

  1. Apache搭建代理服务器
  2. Android手机部分名词浅谈
  3. 软件工程学习进度表(第八周)
  4. 源代码防泄密技术分析
  5. Flask-Mail使用163邮箱异步发送邮件
  6. 【爬虫之路】A站文章围观量B站视频播放量的简单爬虫想法
  7. AOC Q2790PQ 显示器 OSD锁定 解决方法
  8. 开学季需要着重购买哪些物品,大学必备的几款好物分享
  9. Hexo(sakura)+gitee/github搭建个人博客(总结)
  10. 微服务架构-5-Redis实战-5-SpringBoot整合Redis缓存注解开发