ConcurrentHashMap

1.7

1.数据结构:

segment数组 + HashEntry数组 + 链表

2.初始化:

无参的构造函数会初始化一个大小16的Segment数组,并new一个Segment其他都是null

3.put

  • 先计算segment的位置,null的话 用的cas保证只有一个线程 new Segment 赋值进去
  • 再用trylock获取锁(segment继承了Reentrantlock) ,没有获取到的线程会去做点别的事情 ,提前生成好node对象,直到获取到锁
  • 获取到锁后执行hashmap的结点插入,先计算桶的位置

总结:

  • 分段锁提高了并发度。
  • cas + 尝试获取锁保证线程安全

链表插入没法用cas? 所以用锁?

获取了锁为何还用putOrderedObject ,

因为这样保证改的是内存的值, 直接table[i]= 可能只改了线程工作空间的值

怎么加锁的?

尝试获取锁,获取到了走hashmap的插入节点,遍历链表,头插法。

没有获取到锁的线程,循环尝试去获取锁,没有获取到,就会去遍历链表,提前生成node,直到获取到锁。

扩容?

sengment数组不扩容,是hashentry扩容。

1.8

1.数据结构

跟1.8hashmap一样

2.初始化:

  • 没有Segment

  • 无参构造函数啥都没做

3.put:

  • synchronized加锁,只锁一个桶(锁的对象是桶的第一个结点),hashtable锁住整个数组,锁住所有桶。

  • 同时也大量用了cas

如何维护集合长度?

有一个成员变量basecount,修改成功就是它。不成功,里面还有个CounterCell数组,CounterCell里面有个value, 修改不成功就修改另一个CounterCell, 最终数组容量就是basecount + CounterCell的value

size()方法?
  • baseCount + CounterCell数组中的value 累加

强烈建议:构造时要设置初始容量。

  • 容量结果是2的指数次,比你设置的要大。

  • 15 -> 32 16->32 32->64 1->2 0->1

Hashmap1.8的情况是 :设置16的话 数组容量就是16. 5->8


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!