• 解惑如何保证数组元素的可见性(yet)


    https://mp.weixin.qq.com/s?__biz=MzIwMzY1OTU1NQ==&mid=2247484057&idx=1&sn=c5fb63c68203001fa3a0545cef6c0e06&chksm=96cd42d5a1bacbc325759048d6149d49f8c918d8201026fbb1388e1b8f5247d5a147a9e04a24&mpshare=1&scene=1&srcid=0320dLWL3ZptBnHWOIppB46B&key=e372e0f925d47d533edbae8bbd468b84e65f35e0b04cc9bdb6c760a92c8ee6ca4456a735b9106dc2c33ebd40cbce69cf1def258ecd75affb0b7f0783470b16655f19306069e992fab4039316dfeecab8&ascene=0&uin=MTA2NzUxMDAyNQ%3D%3D&devicetype=iMac+MacBookAir6%2C2+OSX+OSX+10.10.5+build(14F2511)&version=11020012&lang=zh_CN&pass_ticket=YOhvdyFJYno3pJPXiaSEWxhPrymv49PNwcVMB6NeX3FSIg%2FYjhsf%2FN9wmUt57lX5

    这篇文章时隔一两年,突然看到还是有点印象,文章中,我只是强硬的抛出了一个结论:虽然table变量被volatile修饰了,但里面的元素并没有volatile修饰,无法保证元素的可见性。

    但是这种解释,似乎被众多的小伙伴怀疑,也一直没有找到有理的证据(基础还是太弱)

    不过在星球中,大家还是很积极的讨论,虽然有些是错的(这种问题在大部分人身上都有,你不表现出来,那你永远不知道自己所掌握的东西其实是不对的)

    解惑

    在ConcurrentHashMap(1.8)中,内部使用一个volatile的数组table保存数据,细心的同学可以发现,Doug Lea每次在获取数组的元素时,采用Unsafe类的getObjectVolatile方法,在设置数组元素时,采用compareAndSwapObject方法,而不是直接通过下标去操作,这是为什么?

    今天得到R大的确认:这个是因为Java数组在元素层面的元数据设计上的缺失,无法表达元素是final、volatile等语义,所以开了后门,使用getObjectVolatile用来补上无法表达元素是volatile的坑,@Stable用来补上final的坑,数组元素就跟没有标volatile的成员字段一样,无法保证线程之间可见性。

    只有触发happens before关系的操作,才能保证线程之间的可见性,比如使用table[0] = new Object()直接赋值,这个赋值不会触发任何happens before关系的操作,相当于对一个无volatile变量进行赋值一样。

    ========================

    Get实现  java.util.concurrent.ConcurrentHashMap.get(Object)

     

     

    Java代码  收藏代码
    1. public V get(Object key) {  
    2.         Segment<K,V> s; // manually integrate access methods to reduce overhead  
    3.         HashEntry<K,V>[] tab;  
    4.         int h = hash(key.hashCode());  
    5.         long u = (((h >>> segmentShift) & segmentMask) << SSHIFT) + SBASE;  
    6.         if ((s = (Segment<K,V>)UNSAFE.getObjectVolatile(segments, u)) != null &&  
    7.             (tab = s.table) != null) {  
    8.             for (HashEntry<K,V> e = (HashEntry<K,V>) UNSAFE.getObjectVolatile  
    9.                      (tab, ((long)(((tab.length - 1) & h)) << TSHIFT) + TBASE);  
    10.                  e != null; e = e.next) {  
    11.                 K k;  
    12.                 if ((k = e.key) == key || (e.hash == h && key.equals(k)))  
    13.                     return e.value;  
    14.             }  
    15.         }  
    16.         return null;  
    17.     }  

     

    get没有使用锁同步,而是使用轻量级同步volatile原语sun.misc.Unsafe.getObjectVolatile(Object, long),保证读到的是最新的对象。

    出自:http://hill007299.iteye.com/blog/1490779

  • 相关阅读:
    QtQuickcontrols2控件使用参考
    QT中VideoProbe的简介和实现
    基于qml创建最简单的图像处理程序(2)使用c++&qml进行图像处理
    在win和android上同时进行OpenCV程序设计
    QTQuick控件基础(3)视图
    ansible循环主机组
    ansible实现template管理变量
    ansible读写系统默认变量
    网络04端口号linux端口详解大全TCP注册端口号大全
    ansible任务委派小技巧
  • 原文地址:https://www.cnblogs.com/silyvin/p/9106613.html
Copyright © 2020-2023  润新知