ConcurrentHashMap的关键部分解析(二)

2014-11-24 12:14:41 · 作者: · 浏览: 1
里就是在找下标啊
if ((s = (Segment )UNSAFE.getObject // nonvolatile; recheck
(segments, (j << SSHIFT) + SBASE)) == null) // in ensureSegment
s = ensureSegment(j);
return s.put(key, hash, value, false);
}

这里给举例解释一下(都是在默认情况下,concurrencyLevel=16,ssize=16,sshift=4)那么 this.segmentShift = 32 - sshift=28 而this.segmentMask = ssize - 1=15二进制就是1111;

如果对于给定的object原来的值分别是15,31,63,127(即 h ^= k.hashCode();//首先先得到初始的hash)

如果不采用再hash操作,那么经过 int j = (hash >>> segmentShift) & segmentMask操作,得到的都是15

经过再hash后得到的hash值分别是:

n块 y锼 У(b~  Т片 i i痕源码吧。

对于put方法来说,也是先定位,再判断是否需要扩充容量,最后插入。这里可以看看和HashMap的不同(提示,二者何时扩充不同,一前一后)

对于size方法来说,这里有些东西还是很值得借鉴的。虽然每个segment都有一个count值表示个个大小,仅仅累加count是不能解决问题的。虽然当时获得的count是最新的但在加的过程中又可能有变化,而仅仅为了得到size就把每个segment的put、remove,clean方法都锁上,代价未免也太大了。因为在累加的过程中count发生变化的几率比较小,那么这里就有一个小的trick,先通过尝试2次不通过锁住segment的方法获取每个大小,如果在统计过程中,count发生变化了,那么再通过加锁的方式进行统计。

那么如何判断是否发生变化了呢,这里modcount就是关键了,每次如put,remove操作都会对modcount进行加1操作,那么只需比较调用size方法之前和之后的modconut大小就知道了。这里值得借鉴啊。

关于ConcurrentHashMap就介绍到这里,有点混乱,说的不是很清晰,但觉得关键的部分说出来了,可以自己再看看源码分析一下,之所以分析一下,是因为在看Ehcache源码的时候,它就是采用和这个类似的类作为仓库的。个人分析可能有误,如有错误请指正。