面试突击19:为什么ConcurrentHashMap不允许插入null值?

简介: 在 Java 语言中,ConcurrentHashMap 和 Hashtable 这些线程安全的集合是不允许 key 或 value 插入 null 值的,而 HashMap 又允许 key 或 value 插入 null 值,这到底是为什么呢?

哈喽,大家好,今天来盘《Java面试突击》系列。

ConcurrentHashMap为什么不允许插入null值?

在Java语言中,ConcurrentHashMap和Hashtable这些线程安全的集合是不允许key或value插入null值的,而HashMap又允许key或value插入null值,这到底是为什么呢?

null值插入演示

首先给HashMap插入null值,实现代码如下:

以上程序的执行结果如下:

从上述结果可以看出,HashMap是允许key或value插入null值的。

接着我们使用同样的方式尝试给ConcurrentHashMap的key和value插入null值,实现代码如下:

编译阶段没有报错,执行以上程序,得到的结果如下:

从上述报错信息可以看出,使用ConcurrentHashMap是不能插入null值的,否者程序在运行期间就会报空指针异常。

PS:Hashtable使用与ConcurrentHashMap类似,这里就不再重复演示了。

ConcurrentHashMap源码分析

为了寻找报错的原因,我们尝试打开ConcurrentHashMap的源码一探究竟。

打开ConcurrentHashMap添加元素的方法put实现源码如下:

从上述源码可以看出,在添加方法的第一句就加了判断:如果key值为null或者是value值为null,就直接抛出异常NullPointerException空指针异常,这就是咱们前面程序报错的原因了。

探索最终原因

通过上面源码分析,我们似乎已经找到了ConcurrentHashMap不允许插入null值的原因,用一句话概括就是:乌龟的屁股“规定”!

然而,这个原因是不能说服面试官的,虽然源码是这样设计的,但我们要思考的是,这样设计背后更深层次的原因,为什么ConcurrentHashMap不允许插入null?而HashMap又允许插入null呢?

二义性问题

所谓的二义性问题是指含义不清或不明确。

我们假设ConcurrentHashMap允许插入null,那么此时就会有二义性问题,它的二义性含义有两个:

  1. 值没有在集合中,所以返回null。
  2. 值就是null,所以返回的就是它原本的null值。

可以看出这就是ConcurrentHashMap的二义性问题,那为什么HashMap就不怕二义性问题呢?

可证伪的HashMap

上面说到HashMap是不怕二义性问题的,为什么呢?

这是因为HashMap的设计是给单线程使用的,所以如果查询到了null值,我们可以通过hashMap.containsKey(key)的方法来区分这个null值到底是存入的null?还是压根不存在的null?这样二义性问题就得到了解决,所以HashMap不怕二义性问题。

不可证伪的ConcurrentHashMap

而ConcurrentHashMap就不一样了,因为ConcurrentHashMap使用的场景是多线程,所以它的情况更加复杂。

我们假设ConcurrentHashMap可以存入null值,有这样一个场景,现在有一个线程A调用了concurrentHashMap.containsKey(key),我们期望返回的结果是false,但在我们调用concurrentHashMap.containsKey(key)之后,未返回结果之前,线程B又调用了concurrentHashMap.put(key,null)存入了null值,那么线程A最终返回的结果就是true了,这个结果和我们之前预想的false完全不一样。

也就是说,多线程的状况非常复杂,我们没办法判断某一个时刻返回的null值,到底是值为null,还是压根就不存在,也就是二义性问题不可被证伪,所以ConcurrentHashMap才会在源码中这样设计,直接杜绝key或value为null的歧义问题。

ConcurrentHashMap设计者的回答

对于ConcurrentHashMap不允许插入null值的问题,有人问过ConcurrentHashMap的作者DougLea,以下是他回复的邮件内容:

以上信件的主要意思是,DougLea认为这样设计最主要的原因是:不容忍在并发场景下出现歧义!

总结

在Java语言中,HashMap这种单线程下使用的集合是可以设置null值的,而并发集合如ConcurrentHashMap或Hashtable是不允许给key或value设置null值的,这是JDK源码层面直接实现的,这样设计的目的主要是为了防止并发场景下的歧义问题。

好了,本期内容到这里就结束了。


是非审之于己,毁誉听之于人,得失安之于数。

公众号:Java面试真题解析

面试合集:gitee.com/mydb/interview

相关文章
|
10月前
|
安全 Java
【Java面试】ConcurrentHashMap的key为什么不允许为null?
【Java面试】ConcurrentHashMap的key为什么不允许为null?
122 0
|
3月前
|
SQL 关系型数据库 MySQL
面试官:MySQL中<>能过滤到null值吗?
引言 了不起最近在定位一个bug的时候,发现本应该过滤出15355条数据的,但其实只过滤出了12891条数据。 然后我就把sql找出来,根据debug调试的参数取到,一执行,果然结果只有12891。 代码大概就像这样的: List<OrderAllotPackage> orderAllotPackageList = orderAllotPackageService.lambdaQuery() .ne(OrderAllotPackage::getTrackingNumber, "") .ne(OrderAllo
39 0
|
5月前
|
存储
不亏是阿里三面,ConcurrentHashMap多线程扩容机制被面试官装到了
不亏是阿里三面,ConcurrentHashMap多线程扩容机制被面试官装到了
|
5月前
|
安全 容器
线程安全的集合类(ConcurrentHashMap面试超高频考点)
线程安全的集合类(ConcurrentHashMap面试超高频考点)
31 0
线程安全的集合类(ConcurrentHashMap面试超高频考点)
|
7月前
|
存储 Java
【面试题精讲】ArrayList 可以添加 null 值吗
【面试题精讲】ArrayList 可以添加 null 值吗
|
7月前
|
Java C++
多线程使用HashMap,HashMap和HashTable和ConcurrentHashMap区别(面试题常考),硬盘IO,顺便回顾volatile(二)
多线程使用HashMap,HashMap和HashTable和ConcurrentHashMap区别(面试题常考),硬盘IO,顺便回顾volatile
|
7月前
|
存储 安全 Java
多线程使用HashMap,HashMap和HashTable和ConcurrentHashMap区别(面试题常考),硬盘IO,顺便回顾volatile(一)
多线程使用HashMap,HashMap和HashTable和ConcurrentHashMap区别(面试题常考),硬盘IO,顺便回顾volatile
|
7月前
|
安全 算法 Java
JUC第十五讲:JUC集合 - 面试 ConcurrentHashMap 看这篇就够了
JUC第十五讲:JUC集合 - 面试 ConcurrentHashMap 看这篇就够了
|
9月前
|
安全 Java C++
为什么ConcurrentHashMap不允许插入null值?
在Java语言中,给ConcurrentHashMap和Hashtable这些线程安全的集合中的Key或者Value插入 null(空) 值的会报空指针异常,但是单线程操作的HashMap又允许 Key 或者 Value 插入 null(空) 值。这到底是为什么呢?
39 0
|
9月前
|
JavaScript