当前位置: 首页 > 科技观察

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

时间:2023-03-15 13:29:09 科技观察

在Java语言中,如果在ConcurrentHashMap、Hashtable等线程安全集合中的Key或Value中插入null(空)值,会报空指针异常,但单线程的HashMap允许Key或Value以插入null(空)值。)价值。为什么是这样?1.探查源码为了找到原因,我们先来看这么一个源码片段,打开ConcurrentHashMap的putVal()方法,源码第一句就做出了很明确的判断,如果Key或Value是null(空)值,直接抛出空指针异常。我们似乎在源代码中找到了原因。你可以这样回答面试官,说JDK源码是这样规定的。但是,这个理由并不能说服面试官。虽然源码是这样设计的,但我们要思考的是这种设计背后更深层次的原因。那么为什么ConcurrentHashMap不允许插入null(空)值,而HashMap允许插入呢?2.二义性问题因为在ConcurrentHashMap中插入null(空)值会造成二义性。我们可以假设ConcurrentHashMap允许插入null(空)值,那么,当我们取值时,会有两种结果:1)该值不在集合中,因此返回结果为null(空);2)值为null(空)),所以返回的结果是它原来的null(空)值。这就产生了歧义的问题。那么HashMap允许插入null(空)值,难道不担心歧义吗?这是因为HashMap是为单线程使用而设计的,所以如果我们得到一个null(空)值,我们可以通过HashMap的containsKey(key)方法来区分这个null(空)值是插入值还是null(空))值,或根本不返回的null(空)值。ConcurrentHashMap则不同,因为ConcurrentHashMap是用在多线程的场景下,它的情况比较复杂。例如,现在一个线程T1调用了ConcurrentHashMap的containsKey(key)方法,我们期望返回结果为false,即T1没有往ConcurrentHashMap中放入null(空)值。然而,却发生了意外。在线程T1得到返回结果之前,线程T2调用了ConcurrentHashMap的put()方法,插入了一个Key,存储的Value为null(空)。然后,线程T1最终得到的返回结果为真。显然,这个结果完全不符合我们之前预期的false。也就是说,在多线程的复杂情况下,在我们多线程的复杂情况下,是插入的null(空)值,还是之前没有返回的null(空)值。换句话说,由此产??生的歧义无法证伪。3、作者回复ConcurrentHashMap不允许插入空值。有人问过ConcurrentHashMap的作者DougLea。以下是他回复的邮件内容:ConcurrentMaps(ConcurrentHashMaps,ConcurrentSkipListMaps)中不允许空值的主要原因是无法容纳在非并发映射中可能勉强可以容忍的歧义。最主要的是,如果map.get(key)返回null,则无法检测键是否显式映射到null与键是否未映射。在非并发映射中,您可以通过map.contains(key)检查这一点,但在并发映射中,映射可能在两次调用之间发生了变化。进一步离题:我个人认为允许在Maps(也包括Sets)中使用null是对程序的公开邀请,以包含在错误的时间中断之前一直未被发现的错误。(即使在非并发的Maps/Sets中是否允许null是JoshBloch和我长期以来一直不同意的围绕集合的少数设计问题之一。)很难检查对于我整个应用程序中的空键和值。在某个地方声明staticfinalObjectNULL=newObject();并用NULL替换所有使用maps的空值会更容易吗?-Doug上面这封信的主要意思是,DougLea认为这样设计的主要原因是:不要容忍并发场景中的歧义!4.总结ConcurrentHashMap在源码中加入了不允许插入null(空)值的设计。主要目的是防止并发场景中的歧义。以上就是我对于ConcurrentHashMap为什么不允许插入null(空)值的解答,明白的朋友请点个关注点个赞,下次才不会迷路。