众所周知,在Java中Map可以存储null,而ConcurrentHashMap不能存储null值,那么为什么呢?
一、先出源码出发
put方法点进去~
@throws NullPointerException if the specified key or value is null and this map does not permit null keys or values
可以清晰的看到源码中规定,ConcurrentHashMap是不可以存储null值的。
二、那么究竟这是为什么呢?
可以先具体的了解一下ConcurrentHashMap。
与HashMap一样,ConcurrentHashMap也是一个基于散列的Map,但它使用了一种完全不同的加锁策略来提供更高的并发性和伸缩性。ConcurrentHashMap并不是将每个方法都在同一个锁上同步并使得每次只能有一个线程访问容器,而是使用一种更细的加锁机制来实现更大程度的共享,这种机制成为分段锁。在这种机制中,任意数量的读取线程可以并发地访问Map,执行读取操作的线程和执行写入操作的线程可以并发地访问Map,并且一定数量的写入线程可以并发地修改Map。ConcurrentHashMap带来的结果是,在并发访问环境下将实现更高的吞吐量,而在单线程环境中只损失非常小的性能。
ConcurrentHashMap返回的迭代器具有弱一致性,而并非“及时失败”。弱一致性的迭代器可以容忍并发的修改,当创建迭代器时会遍历已有的元素,并可以在迭代器被构造后将修改操作反映给容器。ConcurrentHashMap返回的迭代器具有弱一致性,而并非“及时失败”。弱一致性的迭代器可以容忍并发的修改,当创建迭代器时会遍历已有的元素,并可以在迭代器被构造后将修改操作反映给容器。
三、ConcurrentHashMap 作者 Doug Lea 的邮件
对于 ConcurrentHashMap 不允许插入 null 值的问题,有人问过 ConcurrentHashMap 的作者 Doug Lea,以下是他回复的邮件内容:
The main reason that nulls aren’t allowed in ConcurrentMaps
(ConcurrentHashMaps, ConcurrentSkipListMaps) is that ambiguities that
may be just barely tolerable in non-concurrent maps can’t be
accommodated. The main one is that if map.get(key) returns null, you
can’t detect whether the key explicitly maps to null vs the key isn’t
mapped.In a non-concurrent map, you can check this via
map.contains(key),but in a concurrent one, the map might have changed
between calls.Further digressing: I personally think that
allowingnulls in Maps (also Sets) is an open invitation for programsto
contain errors that remain undetected untilthey break at just the
wrong time. (Whether to allow nulls evenin non-concurrent Maps/Sets is
one of the few design issues surroundingCollections that Josh Bloch
and I have long disagreed about.)It is very difficult to check for
null keys and valuesin my entire application .Would it be easier to
declare somewherestatic final Object NULL = new Object();and replace
all use of nulls in uses of maps with NULL?-Doug
以上信件的主要意思是,Doug Lea 认为这样设计最主要的原因是:不容忍在并发场景下出现歧义!