核心问题
- 面试官实际询问的是为什么
ConcurrentHashMap
不能插入null
值。
HashMap与ConcurrentHashMap的区别
-
HashMap:
- 允许
null
作为键(key)和值(value)。 - 单线程环境下使用,非线程安全。
- 允许
-
ConcurrentHashMap:
- 不允许
null
作为键或值。 - 多线程环境下使用,线程安全。
- 不允许
ConcurrentHashMap不允许null
的原因
-
源码层面:
ConcurrentHashMap
的putVal
方法在添加元素时,如果检测到键或值为null
,则会抛出NullPointerException
。 -
设计层面:
ConcurrentHashMap
设计用于并发环境,需要避免二义性问题。- 允许
null
可能导致程序含义不明确或模糊。
二义性问题解释
- 含义:代码或表达式存在多种理解或解释,导致程序含义不明确。
null
的两层含义:- 表示一个具体的“null”值状态。
- 表示“没有”设置值。
HashMap的可证伪性
- 在单线程环境下,
HashMap
可以通过containsKey
等方法区分null
是存入的值还是不存在的值,因此不存在二义性问题。
ConcurrentHashMap的不可证伪性
- 在多线程环境下,其他线程的操作可能影响当前线程的验证结果,导致二义性问题真实存在且不能被证明真伪。
场景
- 线程A检查某个键是否存在,期望返回
false
。 - 线程B在此期间插入了
null
值,导致线程A最终得到的结果与预期不符。
总结
- 为了避免多线程环境下的二义性问题,
ConcurrentHashMap
在源码中禁用了null
值作为键或值。
思考
- 除了
ConcurrentHashMap
,还有哪些容器不允许使用null
作为键或值?