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 协议 ,转载请注明出处!