专栏首页人生得意须尽欢根据 key 计算出对应的 hash 值
原创

根据 key 计算出对应的 hash 值

根据 key 计算出对应的 hash 值

public V put(K key, V value) { 
       if (value == null)          //ConcurrentHashMap 中不允许用 null 作为映射值
           throw new NullPointerException(); 
       int hash = hash(key.hashCode());        // 计算键对应的散列码
       // 根据散列码找到对应的 Segment 
       return segmentFor(hash).put(key, hash, value, false); 
}

  然后,根据 hash 值找到对应的Segment 对象:

/** 
    * 使用 key 的散列码来得到 segments 数组中对应的 Segment 
    */ 
final Segment<K,V> segmentFor(int hash) { 
   // 将散列值右移 segmentShift 个位,并在高位填充 0 ,然后把得到的值与 segmentMask 相“与”,从而得到 hash 值对应的 segments 数组的下标值,最后根据下标值返回散列码对应的 Segment 对象
       return segments[(hash >>> segmentShift) & segmentMask]; 
}

  最后,在这个 Segment 中执行具体的 put 操作:

    V put(K key, int hash, V value, boolean onlyIfAbsent) { 
           lock();  // 加锁,这里是锁定某个 Segment 对象而非整个 ConcurrentHashMap 
           try { 
               int c = count; 
 
               if (c++ > threshold)     // 如果超过再散列的阈值
                   rehash();              // 执行再散列,table 数组的长度将扩充一倍
 
               HashEntry<K,V>[] tab = table; 
               int index = hash & (tab.length - 1); 
               // 找到散列值对应的具体的那个桶
               HashEntry<K,V> first = tab[index]; 
 
               HashEntry<K,V> e = first; 
               while (e != null && (e.hash != hash || !key.equals(e.key))) 
                   e = e.next; 
 
               V oldValue; 
               if (e != null) {            // 如果键值对已经存在
                   oldValue = e.value; 
                   if (!onlyIfAbsent) 
                       e.value = value;    // 替换 value 值
               } 
               else {                        // 键值对不存在 
                   oldValue = null; 
                   ++modCount;         // 要添加新节点到链表中,所以 modCont 要加 1  
                   // 创建新节点,并添加到链表的头部 
                   tab[index] = new HashEntry<K,V>(key, hash, first, value); 
                   count = c;               // 写 count 变量
               } 
               return oldValue; 
           } finally { 
               unlock();                     // 解锁
           } 
       }

  注意:这里的加锁操作是针对某个具体的 Segment,锁定的是该 Segment 而不是整个 ConcurrentHashMap。因为插入键 / 值对操作只是在这个 Segment 包含的某个桶中完成,不需要锁定整个ConcurrentHashMap。此时,其他写线程对另外 15 个Segment 的加锁并不会因为当前线程对这个 Segment 的加锁而阻塞。同时,所有读线程几乎不会因本线程的加锁而阻塞(除非读线程刚好读到这个 Segment 中某个 HashEntry 的 value 域的值为 null,此时需要加锁后重新读取该值)。   相比较于 HashTable 和由同步包装器包装的 HashMap每次只能有一个线程执行读或写操作,ConcurrentHashMap 在并发访问性能上有了质的提高。在理想状态下,ConcurrentHashMap 可以支持 16 个线程执行并发写操作(如果并发级别设置为 16),及任意数量线程的读操作。

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

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

我来说两句

0 条评论
登录 后参与评论

相关文章

  • ddEntry(hash, key, value, i)方法根据计算出的hash值

    ddEntry(hash, key, value, i)方法根据计算出的hash值,将key-value对放在数组table的i索引处。addEntry 是 ...

    用户7365393
  • 根据字符串生成对应Hash值

    参考网址: http://www.partow.net/programming/hashfunctions/

    IBinary
  • JS中的Map如何根据已知的key获取到对应的value值

    一诺千金
  • 面试必会:HashMap 实现原理解读

    HashMap是Java开发当中使用得非常多的一种数据结构,因为其可以快速的定位到需要查找到数据,其最快的速度可以达到O(1),最差的时候也可以达到O(n)。本...

    好好学java
  • HashMap的实现原理

    Tanyboye
  • HashMap的实现原理

    HashMap是基于哈希表的Map接口的非同步实现。此实现提供所有可选的映射操作,并允许使用null值和null键。此类不保证映射的顺序,特别是它不保证该顺序恒...

    哲洛不闹
  • v8源码解析之SymbolTable(v8 0.1.5)

    SymbolTable是哈希表的子类,元素大小是一个Object*。SymbolTable主要使用哈希表来存储字符串,给定一个字符串,算出哈希值,然后插入哈希表...

    theanarkh
  • JDK容器学习之HashMap (一) : 底层存储结构分析

    底层数据结构 首先通过源码,类中的field如下, transient Node<K,V>[] table; transient Set<Map.Entry<...

    一灰灰blog
  • 【深入理解java集合系列】HashMap实现原理

    HashMap是基于哈希表的Map接口的非同步实现。此实现提供所有可选的映射操作,并允许使用null值和null键。此类不保证映射的顺序,特别是它不保证该顺...

    爱笑的架构师
  • HashSet/HashMap详解

    HashMap和HashSet是Java Collection接口两个重要的成员,其中HashMap是Map接口常用的实现类,HashSet是Set接口常用...

    似水的流年
  • JAVA容器-自问自答学ArrayList

    前言 这次我和大家一起学习HashMap,HashMap我们在工作中经常会使用,而且面试中也很频繁会问到,因为它里面蕴含着很多知识点,可以很好的考察个人基础。但...

    java思维导图
  • 小程序根据返回值英文渲染出对应的中文

    需求:后端返回值为英文,在渲染的时候,将英文所对应的中文意识渲染到前端页面。然后每种不同的状态渲染完之后给到不同的颜色进行区分。

    王小婷
  • 小程序根据返回值英文渲染出对应的中文

    需求:后端返回值为英文,在渲染的时候,将英文所对应的中文意识渲染到前端页面。然后每种不同的状态渲染完之后给到不同的颜色进行区分。

    王小婷
  • Java数据结构-------Map

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

    在周末
  • 大牛带你深入解读HashMap

    HashMap 和 HashSet 是 Java Collection Framework 的两个重要成员,其中 HashMap 是 Map 接口的常用实现类,...

    慕容千语
  • Java中HashMap详解

    HashMap 和 HashSet 是 Java Collection Framework 的两个重要成员,其中 HashMap 是 Map 接口的常用实现类,...

    哲洛不闹
  • HashMap源码分析-jdk1.6和jdk1.8的区别【面试+工作】

    在java集合中,HashMap是用来存放一组键值对的数,也就是key-value形式的数据,而在jdk1.6和jdk1.8的实现有所不同。

    Java帮帮
  • HashMap源码解析(一)

    HashMap是面试中经常被问到的一个问题,不管是初级还是中级以及高级,都会问到,只不过深度不一样,今天我们就详细解析一下HashMap的源码,为了大家能碎片时...

    小土豆Yuki
  • SparkSQL的3种Join实现

    Join是SQL语句中的常用操作,良好的表结构能够将数据分散在不同的表中,使其符合某种范式,减少表冗余、更新容错等。而建立表和表之间关系的最佳方式就是Join操...

    王知无-import_bigdata

扫码关注云+社区

领取腾讯云代金券