码迷,mamicode.com
首页 > 其他好文 > 详细

【JDK源码系列】ConcurrentHashMap

时间:2015-09-15 14:45:11      阅读:198      评论:0      收藏:0      [点我收藏+]

标签:

ConcurrentHashMap的关键实现:分段锁,简单来讲就是将hash表分成一段段子表,分别加锁。本质上ConcurrentHashMap和hashMap没什么区别,元素都是Entry,一个节点加链表。发生冲突的时候采用链表法存储元素,所以源码里会有大量的通过key的hash值找到槽后进行遍历查询的操作。

下面是子表的源码实现:

技术分享

自定义了一个segment类,继承了可重入锁。可以看一下整体的结构:

技术分享

其中比较关键的应该是put,rehash,scanandlock,remove,replace等方法。

我们先来看segment的put方法:

对map中的某个segment做put操作,加入我们来实现一般会考虑到几点:

  1. 需要加锁,因为要考虑到key相同的情况,如果不加锁,两个线程同时更新同一个key的value,会出错。
  2. 需要考虑锁已经被占的情况。
  3. 需要更新segment的元素个数。
  4. 需要考虑segment扩容的问题。

带着这些考虑,我们再来看源码可能就会更有针对性一些。

技术分享

第一步果然是加锁,这里直接用了trylock,因为segment继承了可重入锁,其实这是个很垃圾的设计,按理来说应该优先使用组合而不是继承。我们可以看到,尝试获取锁失败后,调用了scanAndLockForPut方法,这个方法会不断尝试获取锁,同时去匹配entry的key值,直到成功,重新回到put方法。

Put方法里考虑到了扩容的问题:

技术分享

假如元素个数大于阈值,会调用rehash方法。Rehash首先进行了数组的扩容:

技术分享

同时对老的元素进行迁移的时候进行了rehash操作: idx = e.hash&sizeMask

技术分享

最后put方法会更新元素总数:

技术分享

下面我们来看一下remove方法:

同样的我们首先来自己思考一下哪些点是需要考虑到的:

  1. 需要枷锁,同时考虑锁被抢占,同插入
  2. 更新元素个数

首先是尝试获取锁,如果锁被占了,那么等待获取。

技术分享

查找的时候先获取Entry,然后遍历链表:

技术分享

找到元素后进行普通的链表移除元素操作,并更新元素总数。

技术分享

这里有点奇怪的地方,modeCount为什么加一了?这点后面解答。

Replace和remove操作几乎一致,这里不再赘述。

【JDK源码系列】ConcurrentHashMap

标签:

原文地址:http://www.cnblogs.com/AlwaysFixBug/p/4810032.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!