JUC源码分析(一):ConcurrentHashMap集合分析

ConcurrentHashMap类继承至AbstractMap 实现接口ConcurrentMap,Serializable

这个类有以下主要的几个静态变量

DEFAULT_INITIAL_CAPACITY=16 初始化数组长度

DEFAULT_LOAD_FACTOR=0.75 默认装载因子

DEFAULT_CONCURRENCY_LEVEL=16 默认并发级别

MAXIMUM_CAPACITY=1<<30 最大数组长 1<<30

MIN_SEGMENT_TABLE_CAPACITY=2 最小桶长度 

MAX_SEGMENTS=1<<16 最大桶数量

接下来是ConcurrentHashMap的构造器

1.可以注意到其中的运算 sshift是并发级别的角标 注意 这里的concurrencyLevel是2的倍数

ssize可以近似看作是concurrencyLevel

2。创建了一个桶对象 s0,和一个桶的数组长度为ssize

这里的HashEntry结构如图

四个变量分别为 key,(volatile修饰保证内存可见性)value,key的hash值(hash) 还有一个用volatile变量修饰的HashEntry元素指针 指向下一个元素

桶segment的类结构如下

桶的主要元素 是一个HashEntry的数组变量和一切其他信息

所以 整个ConcurrentHashMap的结构是一个数组(segment)数组的每一个元素还是一个(HashEntry)数组

接下来看一下put方法

这里的seqmentShift是通过并发等级得到的值 并发等级为N

则segmentShift=32-a,这里得a=log2 N。2为底N为幂 的对数值

这里的J相当于取 他的key的hash值得高a位

通过ensureSegment方法去获取 hash值所在得桶segment对象 注意 在ConcurrentHashmap里面获取对象都是通过UNSAFE.getObjectVolatile去获取得 并且通过CAS(compareAndSwap)算法 去比较赋值 这是保证在高并发下数据保持一致得一种算法

CAS算法 是 有三个值 一个原始值K,一个修改值B,一个预估值A

在修改得时候 先比较原始值 和预估值(在预估值上进行计算得到修改值),当且这两个值相等的时候,才将修改值 写入内存

可以看到

1.加锁

2.调用桶 segment得put方法,通过拿到得桶对象,获取第一个HashEntry数组元素,依次往下遍历,第一个IF判断里是HashEntry[] 里有相同得Key值元素得时候 进行值替换操作 并且控制角标往数组下方移动

3.else里面则是当角标移动到数组最后一位得时候进行元素得新建操作

4.解锁

可以看到,整个ConcurrentHashMap是一个数组加数组得结构 

其中HashEntry 在内存上连续 在结构上除了可以通过index关联 也通过next指针关联在一起

在对每一个桶(segment)操作得时候 对其中得HashEntry[](表结构)会进行加锁(trylock)和解锁(unlock)操作 这就是ConcurrentHashMap得分段锁机制。将每一个桶单独做成一个HashMap结构 在高并发得时候 以表结构为单位进行操作。并且通过CAS算法 确保了数据得一致性。所以 ConcurrentHashMap相较于Hashtable而言是效率更高得 相对于HashMap而言 是线程安全得

猜你喜欢

转载自my.oschina.net/u/2970507/blog/1821972