likes
comments
collection
share

你知道ConcurrentHashMap 为什么 key 和 value 不能为 null,而HashMap的key和value都可以为null吗?

作者站长头像
站长
· 阅读数 22

首先指明:HashMap 可以存储 null 的 key 和 value,但 null 作为键只能有一个,null 作为值可以有多个。这也是ConcurrentHashMap和HashMap的区别之一。

直接上源码:

HashMap#putVal()代码片段:

    final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
        else {

ConcurrentHashMap#putVal()代码片段:

    final V putVal(K key, V value, boolean onlyIfAbsent) {
        if (key == null || value == null) throw new NullPointerException();
        int hash = spread(key.hashCode());
        int binCount = 0;
        for (Node<K,V>[] tab = table;;) {
            Node<K,V> f; int n, i, fh;
            if (tab == null || (n = tab.length) == 0)
                tab = initTable();
            else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
                if (casTabAt(tab, i, null,
                             new Node<K,V>(hash, key, value, null)))
                    break;                   // no lock when adding to empty bin
            }

直观上就能看出ConcurrentHashMap调用put(key, value)时,对key,value都进行判空处理,而HashMap并没有。这样设计的原因直接来看看作者的回答:

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.

翻译过来就是单线程情况下(HashMap)可以容忍歧义性,所谓的歧义看下面,但是多线程并发(ConcurrentHashMap)不能容忍歧义性,因为并发包的map,调用之间的map可能发生了变化,所以歧义性再加上多线程并发操作是不能容忍的,会加重设计的复杂度和曲折性

这就是作者这么设计的原因吧

ConcurrentHashMap 的 key 和 value 不能为 null 主要是为了避免模棱两可歧义性:就拿#get(key)方法获取value值说说上面提到的歧义性:返回null有两种情况:

① map中没有这个key-value键值对,返回null

② map中有这个key-value键值对,但是value值为null,此时也返回null

这就上面所说的歧义,也就是二义性。