ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

JDK1.7-ConcurrentHashMap原理

2021-10-20 16:35:03  阅读:189  来源: 互联网

标签:ConcurrentHashMap 分段 JDK1.7 数组 链表 HashEntry 哈希 原理 Segment


结构

  • ConcurrentHashMap中有一个Segment数组。每个Segment表示一个分段锁。
  • 每个Segment对象中,有一个HashEntry数组。
  • 每个HashEntry表示一个键值对。HashEntry还有一个next属性,可以形成一个链表。
  • 每个Segment实例都有一个count来表示该分段包含的HashEntry“Key-Value对”总数,即HashEntry的总数。
  • 之所以在每个Segment实例中包含一个计数器,而不是在ConcurrentHashMap中使用全局的计数器,是为了避免出现“全局热点”而影响并发性。
  • 在HashEntry类中,key、hash和next字段都被声明为final型,value字段被声明为volatile型。
  • 在ConcurrentHashMap中,哈希时如果产生“碰撞”,将采用“分离链接法”来处理:把“碰撞”的HashEntry对象链接成一个链表,形成一个桶。由于HashEntry的next字段为final型,因此新节点只能在链表的表头处插入。链表顺序,与插入的顺序相反。

get操作

  • 根据key,计算哈希码
  • 根据哈希码,计算分段锁在数组中的索引。
  • 根据分段锁在数组中的索引,获取分段锁对象,并取到其中的table(HashEntry数组)。通过UNSAFE.getObjectVolatile()方法操作,从主存中读取,确保读到最新的值。
  • 根据哈希码,取到HashEntry对象,也即一个链表,再对链表进行遍历。
  • 遍历过程中,根据key和hash,找到对应元素的value,返回。
  • get为只读操作,不修改内容,所以不加锁。但要保证多线程的可见性。

put操作

说明:

  • 有两个添加方法,put,putIfAbsent。
  • 分段锁的put操作,是要进行加锁的。

操作步骤:

  • 根据key,计算哈希码
  • 根据哈希码,计算分段锁在数组中的索引。
  • 根据分段锁索引,获取分段锁,如果获取到的为空,则构造一个。UNSAFE.getObject()方法。
  • 调用分段锁的put方法添加元素。
  • 下面是分段锁的put方法逻辑。
  • 加锁,成功后继续。
  • 根据哈希码,计算出对象HashEntry对象的下标。
  • 根据下标,取出HashEntry对象,即一个链表。也可能取到空。
  • 如果取到的是一个非空的链表,遍历链表。如果找到对应的HashEntry,根据onlyIfAbsent,决定是否替换。
  • 如果取到的是空,或上一步直至最终也没有找到匹配元素,则在链表头部添加一个节点,表示本次要添加的元素。
  • 将此Segment中的元素总数计数器:count加1
  • 若元素超过阈值,则进行扩容。否则,将HashEntry数组的下标指标新增的HashEntry元素。因为此元素,是链表的头节点了。调用UnSafe的putOrderedObject()方法来更改数组元素引用,这样就保证了其他线程在读取时可以读到最新的值

--结束--

标签:ConcurrentHashMap,分段,JDK1.7,数组,链表,HashEntry,哈希,原理,Segment
来源: https://www.cnblogs.com/shangyingbin/p/15429398.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有