考察目标
这是一个基础问题,主要考察 1 到 3 年经验的开发人员
ConcurrentHashMap 在实际应用中使用频率较高
考察这个问题的目的,是了解求职者的基本功。
所以为了表现更好,可以从 ConcurrentHashMap 的设计角度去回答。
问题解析
打开 ConcurrentHashMap 的源码
在 put 方法里面,可以看到这样一段代码(如图)
如果 key 或者 value 为空,则抛出空指针异常。
但是为什么 ConcurrentHashMap 不允许 key 或者 value 为空呢?
简单来说,就是为了避免在多线程环境下出现歧义问题。
所谓歧义问题,就是如果 key 或者 value 为 null,当我们通过 get(key)获取对应的 value
的时候,如果返回的结果是 null
我们没办法判断,它是 put(k,v)的时候,value 本身为 null 值,还是这个 key 本身就不
存在。
比如在这样一种情况下(如图),线程 t1 调用 containsKey 方法判断 key 是否存在,
假设当前这个 key 不存在,本来应该返回 false。
但是在 T1 线程返回之前,正好有一个 T2 线程插入了这个 key,但是 value 为 null。
这就导致原本 T1 线程返回的结果有可能是 true,有可能是 false,取决于 T1 和 T2 线 程的执行顺序
这种现象我们可以认为是线程安全性问题,而 ConcurrentHashMap 又是一个线程安
全的集合,
所以自然就不允许 key 或者 value 为 null。
而 HashMap 中是允许存 null 的,因为它不需要考虑到线程安全性问题。
所以这个问题的核心本质还是 ConcurrentHashMap 这个并发安全性集合的特性。
当然。Doug Lea 还认为,不管是否是并发安全的集合,它都不应该允许存储 null。
高手回答
好的。
ConcurrentHashMap 这么设计的原因是为了避免在多线程并发场景下的歧义问题。
也就是说,当一个线程从 ConcurrentHashMap 获取某个 key,如果返回的结果是 null
的时候。
这个线程无法确认,这个 null 表示的是确实不存在这个 key,还是说存在 key,但是
value 为空。
这种不确定性会造成线程安全性问题,而 ConcurrentHashMap 本身又是一个线程安
全的集合。
所以才这么设计!
以上就是我的理解。
摘自mic老师文档