ConcurrentHashMap为何不支持null键和null值

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ConcurrentHashMap为何不支持null键和null值相关的知识,希望对你有一定的参考价值。

参考技术A 最近在梳理总结 《集合 - 常用Map之间区别》 , 其中有一点就是 HashMap 是支持null键和null值,而 ConcurrentHashMap 是不支持的;

后来查看了一下jdk源码,证明了确实是这样的。

HashMap.java 部分源码

ConcurrentHashMap.java 部分源码

ConcurrentHashMap不能put null 是因为 无法分辨是key没找到的null还是有key值为null,这在多线程里面是模糊不清的,所以压根就不让put null。

ConcurrentHashmap和Hashtable都是支持并发的,这样会有一个问题,当你通过get(k)获取对应的value时,如果获取到的是null时,你无法判断,它是put(k,v)的时候value为null,还是这个key从来没有做过映射。HashMap是非并发的,可以通过contains(key)来做这个判断。而支持并发的Map在调用m.contains(key)和m.get(key),m可能已经不同了。

Java中ConcurrentHashMap的实现


Java中ConcurrentHashMap的实现

      ConcurrentHashMap(简写CHM)引入了分割,并提供了HashTable支持的所有的功能。在CHM中,支持多线程对Map做读操作,并且不需要任何的blocking。这得益于CHM将Map分割成了不同的部分,在执行更新操作时只锁住一部分。根据默认的并发级别(concurrency level),Map被分割成16个部分,并且由不同的锁控制。这意味着,同时最多可以有16个写线程操作Map。试想一下,由只能一个线程进入变成同时可由16个写线程同时进入(读线程几乎不受限制),性能的提升是显而易见的。但由于一些更新操作,如put(),remove(),putAll(),clear()只锁住操作的部分,所以在检索操作不能保证返回的是最新的结果。

       另一个重要点是在迭代遍历CHM时,keySet返回的iterator是弱一致和fail-safe的,可能不会返回某些最近的改变,并且在遍历过程中,如果已经遍历的数组上的内容变化了,不会抛出ConcurrentModificationExceptoin的异常。

      CHM默认的并发级别是16,但可以在创建CHM时通过构造函数改变。毫无疑问,并发级别代表着并发执行更新操作的数目,所以如果只有很少的线程会更新Map,那么建议设置一个低的并发级别。另外,CHM还使用了ReentrantLock来对segments加锁。

什么时候使用ConcurrentHashMap

        CHM适用于读者数量超过写者时,当写者数量大于等于读者时,CHM的性能是低于Hashtable和synchronized Map的。这是因为当锁住了整个Map时,读操作要等待对同一部分执行写操作的线程结束。CHM适用于做cache,在程序启动时初始化,之后可以被多个请求线程访问。正如Javadoc说明的那样,CHM是HashTable一个很好的替代,但要记住,CHM的比HashTable的同步性稍弱。


以上是关于ConcurrentHashMap为何不支持null键和null值的主要内容,如果未能解决你的问题,请参考以下文章

ConcurrentHashMap不支持null

为什么Hashtable ConcurrentHashmap不支持key或者value为null

源码解读JDK1.8 中 ConcurrentHashMap 不支持空键值对源码剖析

什么?你不知道 ConcurrentHashMap 的 kv 不能为 null?

什么?你不知道 ConcurrentHashMap 的 kv 不能为 null?

Java中ConcurrentHashMap的实现