前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >根据 key 计算出对应的 hash 值

根据 key 计算出对应的 hash 值

原创
作者头像
用户7365393
修改2021-10-08 15:20:16
1.3K0
修改2021-10-08 15:20:16
举报
文章被收录于专栏:人生得意须尽欢

根据 key 计算出对应的 hash 值

代码语言:javascript
复制
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 对象:

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

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

代码语言:javascript
复制
    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),及任意数量线程的读操作。

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

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 根据 key 计算出对应的 hash 值
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档