视频地址:https://kaiwu.lagou.com/course/courseInfo.htm?courseId=1131
你好,我是胡书敏,这一讲我们通过分析 ConcurrentHashMap 底层源码,讲讲 Java 线程并发。
我在面试候选人的时候,为了考核求职者在高并发方面的开发技能,所以经常会问到关于 ConcurrentHashMap、线程并发,或者如何解决 OOM 问题等问题。实际情况是,只有少部分候选人能够抓住重点。
我们大多数程序员都是业务开发者,要知道,在面试官眼里,如果没有 3 到 5 年的开发经验,未必能围绕底层源码,全面掌握并展示线程和排查 OOM 问题等技能。但如果求职者能够通过 ConcurrentHashMap 这个切入点全面展示技能,那么就能很大程度上提升面试成功的可能性。
接下来,我就从底层源码和技术面试这两个角度,全面分析下 ConcurrentHashMap 对象。
首先会通过底层源码,从线程并发角度,分析读写 ConcurrentHashMap 对象的详细做法,然后,在此基础上教你如何在面试中展示这方面的亮点;不仅如此,还会教你在面试中展示“通过分析源码排查 OOM 问题”的说辞。
ConcurrentHashMap 是以键值对的形式存储数据,在 JDK 1.8 及之上的版本里,ConcurrentHashMap 对象会用 node 数组(左图)或红黑树(右图)的方式存储键值对类型的数据,如下图所示。
之所以用两种方式来存储,主要是因为当 ConcurrentHashMap 里存储的键值对出现冲突,且冲突的数量比较多时,用右图红黑树的方式能够提升数据读写的性能。ConcurrentHashMap 用来存储键值对的 Node 对象如下所示,其中包含了面试热点“volatile 关键字”,在下文中我们会具体分析。
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
volatile V val;
volatile Node<K,V> next;
通过 Node 源码可以看到,其中用 key 和 value 存储键值对,如果遇到冲突,则用 next 对象指向下一个具有相同 key 的 Node 对象。这里请你思考,为什么要在 val 和 next 变量前加 volatile ?下面我们具体分析一下。
在多个线程同时写一个 ConcurrentHashMap 对象时,线程内存和主内存的关系如下图所示。