Java1.7下的ConcurrentHashMap【简要总结】

来源:互联网 发布:c语言从单数1加到100 编辑:程序博客网 时间:2024/05/29 16:41

ConcurrentHashMap是线程安全的,通过分段锁的方式提高了并发度。分段是一开始就确定了,后期不能再进行扩容。

其中段Segment继承了重入锁ReentrantLock,有了锁的功能,同时含有类似HashMap数组加链表的结构。

虽然Segment的个数是不能扩容的,但是单个Segment里面的数组是可以扩容的。


ConcurrentHashMap3个参数:

initialCapacity:初始总容量:默认16

loadFactor:加载因子,默认0.75

concurrencyLevel:并发级别,默认16

然后我们需要知道的是:

segment的个数即ssize

取大于等于并发级别的最小的2的幂次。如concurrencyLevel=16,那么ssize=16,如concurrencyLevel=10,那么ssize=16

单个segment的初始容量cap

c=initialCapacity/ssize,并且可能需要+1(即向上取整)。如15/7=2,那么c3,如16/8=2,那么c2cap取的值就是大于等于c的最小2的幂次。但是cap最小值要求是2

单个segment的阈值threshold

通过cap*loadFactor计算得出。

所以,默认情况下,segment的个数ssize=16,每个segment的初始容量是cap=2,单个segment的阈值threshold=1


put过程

1、首先根据key计算出一个hash值,找到对应的Segment

2、调用Segmentlock方法,为后面的put操作加锁

3、根据key计算出hash值,找到Segment中数组中对应的index的链表,并将该数据放置到链表中

4、判断当前Segment包含元素的数量大于阈值,则Segment进行扩容


扩容过程

这个扩容过程是在Segment的锁的保护下进行扩容的,不需要关注并发问题。

这里的重点就是:

首先找到一个lastRunlastRun之后的元素和lastRun是在一个桶中,所以后面的不需要进行变动。

然后对开始到lastRun部分的元素,重新计算下设置到newTable中,每次都是将当前元素作为newTable的首元素,之前老的链表作为该首元素的next部分。


get过程

1、通过key计算出对应的segment

2、再根据key计算出对应segment中数组的index

3、最终遍历上述index位置的链表,查找出对应的keyvalue

0 0
原创粉丝点击