专栏首页人生得意须尽欢get的过程中另一个线程恰好新增entry
原创

get的过程中另一个线程恰好新增entry

public V get(Object key) {
    int hash = hash(key); // throws NullPointerException if key null
    return segmentFor(hash).get(key, hash);
}
V get(Object key, int hash) { 
           if(count != 0) {       // 首先读 count 变量
               HashEntry<K,V> e = getFirst(hash); 
               while(e != null) { 
                   if(e.hash == hash && key.equals(e.key)) { 
                       V v = e.value; 
                       if(v != null)            
                           return v; 
                       // 如果读到 value 域为 null,说明发生了重排序,加锁后重新读取
                       return readValueUnderLock(e); 
                   } 
                   e = e.next; 
               } 
           } 
           return null; 
       }

  ConcurrentHashMap完全允许多个读操作并发进行,读操作并不需要加锁。关键是用 HashEntry 对象的不变性来降低读操作对加锁的需求。只是判断获取的entry的value是否为null,为null时才使用加锁的方式再次去获取。   在代码清单“HashEntry 类的定义”中我们可以看到,HashEntry 中的 key,hash,next 都声明为 final 型。这意味着,不能把节点添加到链接的中间和尾部,也不能在链接的中间和尾部删除节点。这个特性可以保证:在访问某个节点时,这个节点之后的链接不会被改变。这个特性可以大大降低处理链表时的复杂性。 下面分析在get的时候的线程安全性

get的过程中另一个线程恰好新增entry

  HashEntry 类的 value 域被声明为 volatile 型,Java 的内存模型可以保证:某个写线程对 value 域的写入马上可以被后续的某个读线程“看”到。在 ConcurrentHashMap 中,不允许用 null 作为键和值,当读线程读到某个 HashEntry 的 value 域的值为 null 时,便知道发生了指令重排序现象(注意:volatile变量重排序规则,同时也是先行发生原则的一部分:对一个volatile变量的写操作先行发生于后面对这个变量的读操作,这里的“后面”同样是指时间上的先后顺序。所以,在tab[index] = new HashEntry<K,V>(key, hash, first, value);中,可能会出现当前线程得到的newEntry对象是一个没有完全构造好的对象引用。),需要加锁后重新读入这个 value 值。

如果get的过程中另一个线程修改了一个entry的value

  由于对 volatile 变量的可见性,写线程对链表的非结构性修改能够被后续不加锁的读线程“看到”。

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

关注作者,阅读全部精彩内容

我来说两句

0 条评论
登录 后参与评论

相关文章

  • get的过程中另一个线程删除一个entry

    假设我们的链表元素是:e1-> e2 -> e3 -> e4 我们要删除 e3这个entry   因为HashEntry中next的不可变,所以我们无法直接把...

    用户7365393
  • ConcurrentHashMap原理分析

    ConcurrentHashMap是Java5中新增加的一个线程安全的Map集合,可以用来替代HashTable。对于ConcurrentHashMap是如何提...

    一觉睡到小时候
  • Netty源码阅读入门实战(十)-性能优化1 性能优化工具类

    ThreadLocal最常用的两个接口是set和get 最常见的应用场景为在线程上下文之间传递信息,使得用户不受复杂代码逻辑的影响

    JavaEdge
  • Java多线程编程-(11)-面试常客ThreadLocal出现OOM内存溢出的场景和原理分析

    1、首先看一下代码,模拟了一个线程数为500的线程池,所有线程共享一个ThreadLocal变量,每一个线程执行的时候插入一个大的List集合:

    Java后端技术
  • 详述 ThreadLocal 的实现原理及其使用方法

    Threadlocal是一个线程内部的存储类,可以在指定线程内存储数据,并且该数据只有指定线程能够获取到,其官方解释如下:

    CG国斌
  • 面试又被问懵了吗?不如把ThreadLocal拆开了揉碎看看

    所谓并发,就是有限资源需要应对远超资源的访问。解决问题的方法,要么增加资源应对访问;要么增加资源的利用率。 所以,相信这年头做开发的多多少少,都会那么几个“线程...

    Java程序猿阿谷
  • hashMap

    https://www.cnblogs.com/skywang12345/category/455711.html

    大学里的混子
  • HashMap面试题,看这一篇就够了!

    在后端的日常开发工作中,集合是使用频率相当高的一个工具,而其中的HashMap,则更是我们用以处理业务逻辑的好帮手,同时HashMap的底层实现和原理,也成了面...

    天之痕苏
  • 线程的私有领地 ThreadLocal

    从名字上看,『ThreadLocal』可能会给你一种本地线程的概念印象,可能会让你联想到它是一个特殊的线程。

    Single
  • HashMap 与 ConcrrentHashMap 使用以及源码原理分析

    数组:采用一段连续的存储单元来存储数据。对于指定下标的查找,时间复杂度为O(1);通过给定值进行查找,需要遍历数组,逐一比对给定关键字和数组元素,时间复杂度为...

    小勇DW3
  • HashTable原理和底层实现

    上次讨论了HashMap的结构,原理和实现,本文来对Map家族的另外一个常用集合HashTable进行介绍。HashTable和HashMap两种集合非常相似,...

    用户6182664
  • [Java集合] 彻底搞懂HashMap,HashTable,ConcurrentHashMap之关联.

    注: 今天看到的一篇讲hashMap,hashTable,concurrentHashMap很透彻的一篇文章, 感谢原作者的分享. 原文地址: h...

    一枝花算不算浪漫
  • ThreadLocal 源码解析

    多线程访问共享可变数据时,涉及到线程间数据同步的问题。并不是所有时候,都要用到 共享数据,所以线程封闭概念就提出来了。

    JavaEdge
  • Java数据结构-------Map

        1)无序; 2)访问速度快; 3)key不允许重复(只允许存在一个null Key);

    在周末
  • 你知道HashMap在高并发下可能会出现哪些问题吗

    我们都知道,HashMap在并发环境下使用可能出现问题,但是具体表现,以及为什么出现并发问题, 可能并不是所有人都了解,这篇文章记录一下HashMap在多线程环...

    田维常
  • ThreadLocal原理分析与代码验证

    ThreadLocal提供了线程安全的数据存储和访问方式,利用不带key的get和set方法,居然能做到线程之间隔离,非常神奇。

    明年我18
  • Java面试必问,深入理解 ThreadLocal 实现原理与内存泄露

    在面试环节中,考察"ThreadLocal"也是面试官的家常便饭,所以对它理解透彻,是非常有必要的.

    用户2781897
  • 猿思考系列9——一文获取隐藏逻辑挖掘办法

    看完上一个章节,相信你已经充分的掌握了数据库事务的一些事情,猿人工厂君也知道,内容对于新手而言,理解起来还是比较很吃力的,文中提到的原理和内容,有兴趣的可以和我...

    山旮旯的胖子
  • java中HashMap详解

    通过HashMap、HashSet 的源代码分析其 Hash 存储机制 实际上,HashSet 和 HashMap 之间有很多相似之处,对于 HashSet ...

    哲洛不闹

扫码关注云+社区

领取腾讯云代金券