落叶知秋|ConcurrentHashMap确实很复杂,这样学源码才简单
之前在写HashMap的底层实现原理和设计背景的时候(看我主页置顶文章) , 有读者朋友反馈想看ConcurrentHashMap方面的文章 , 今天为大家带来这篇文章 。
ConcurrentHashMap相对HashMap来说要复杂的多 , HashMap涉及到的知识点相对较少 , 无非就是数组、链表、红黑树、哈希碰撞、扩容这些东西 , 但是ConcurrentHashMap涉及到的知识点却比这些要多 , 因为一旦涉及到多线程环境下的并发安全 , 并发、同步、锁这些概念就得了解 。
而在实际coding中 , HashMap使用频率很高 , ConcurrentHashMap却很低甚至没有 , 这就增加了我们学习的门槛 。
1、学习思路学习ConcurrentHashMap之前 , 必须要清晰掌握HashMap的实现原理!
因为HashMap不是线程安全的 , 所以我们需要有一个线程安全的HashMap , 能够保证线程安全的有:
HashTable、
Collections.synchronizedMap()、
ConcurrentHashMap ,
然而HashTable、Collections.synchronizedMap()的实现方式是直接上锁的 , 性能方面没有做到最优解 , 因此我们需要一个性能更好的 , 这就是ConcurrentHashMap产生的背景 。
所以我们需要搞清楚以下一些问题:
- HashMap的底层原理;
- HashMap的哪些地方是线程不安全的?
- HashTable、Collections.synchronizedMap()、ConcurrentHashMap都是如何保证线程安全的?
- 为什么HashTable、Collections.synchronizedMap()没人提了 , ConcurrentHashMap却满天飞、逢面必问呢?
- 面试官问你ConcurrentHashMap真正要考察的知识是什么?
本文源码基于JDK1.8 。
2、HashMap中的那些线程不安全的操作关于HashMap的实现原理 , 你必须熟记于心 , 然后我们才能继续去学习ConcurrentHashMap , 这里一张图来回顾一下HashMap的数据结构:
HashMap底层数据结构
如果对HashMap底层实现原理不熟悉的可以先行阅读我的文章:
如果你这么去理解HashMap就会发现它真的很简单
接下来我们就进入HashMap的源码中来发现那些线程不安全的操作 。
3、线程不安全一:数组初始化当我们初始化一个HashMap的时候 , 他其实只是定义了initialCapacity和loadFactor这两个值 , 并没有初始化数组 , 而是懒加载的思想 , 在第一次put时候通过resize()方法去加载 。
HashMap.put()方法源码
进入resize()方法 , 前面一堆计算拿到要初始化数组的大小newCap , 最终执行new Node[newCap];来初始化数组:
数组初始化
为什么线程不安全?
如果上面的这段话是被两个线程来执行会出现什么情况?
当线程T1和T2同时去put一个值执行putVal()的时候 , 会是什么情况?
if ((tab = table) == null || (n = tab.length) == 0)n = (tab = resize()).length;
例如:- T1线程的任务是初始化数组长度为16 , T2线程的任务是初始化数组长度为32 , 是不是就无法得到一个确定的数组了?
- 落叶知秋|跨境易税通应邀参加海关总署跨境电商研讨会
- 新鲜事儿|《浪姐》30岁蓝盈莹又被骂上热搜:这一次,确实是她不“懂事”了
- 落叶知秋|手机有这三种情况的,还是换了吧,别委屈自己
- 如今热刺俱乐部确实非常受欢迎,估计接下来穆里尼奥还会锁定新目标,然后完成签约
- 新机发布华为Mate40 Pro爆料:钢化膜曝光,确实很霸气!
- 加图索|加图索:我确实应被罚下,已经想好踢巴萨的阵容
- 发卡|杨幂为了显头发厚实也是拼了,带8个发卡定型,确实看着很蓬松
- 放料|“业内”真的放料了肖战“真实”数据大揭秘,前景确实堪忧
- 塞尔吉-奥利耶|马尔蒂尼:伊布在下赛季球队计划内,确实与奥利耶团队有过接触
- #金庸#王朔骂金庸就一俗人,写武侠只知见面打架,金庸说:我确实没本事