Map中value赋值null记录一下

925 阅读2分钟

无意义的开头

  • 在java集合容器里使用较多的有Map集合有HashMap和ConcurrentHashMap。
  • 其中HashMap为非线程安全,只有在单线程内或并发读场景里使用。而ConcurrentHashMap为线程安全集合。
  • 根据这两者使用场景的不同,可以解析出集合value赋值为null的两义性问题。

分析流程

  • 先上图 在这里插入图片描述

  • 上图里是HashMap集合中添加元素的方法源码,里面很明显没有对输入的key和value进行是否为null的判断。 在这里插入图片描述

  • 上张图里是ConcurrentHashMap集合中添加元素的方法源码,在putVal()方法的第一行就对key和value进行了非null的判断。 在这里插入图片描述

  • 那么这两个集合都是继承自Map,为什么在添加元素时一个需要验证是否为null,另一个不需要验证呢?

  • 其实就要和它们的使用场景有关了

  • 在HashMap中一般多是使用在单线程或高并发读的场景里。那么如果HashMap.get(key)获取值null,这时就会有两种情况:一种是集合里没有对应的key,一种是集合里有key设置了一个null值。这里就存在两义性。然后可以使用HashMap.containsKey(key)方法来判断当前属于那种情况,这样就又能解决两义性。
  • 在ConcurrentHashMap中一般多使用在多线程场景里。如果ConcurrentHashMap也允许value可以为null,那么当ConcurrentHashMap.get(key)获取值null也会存在上述的两义性,但却无法用containsKey(key)方法来解决两义性。因为线程A调用get(key)方法取值结果为null,然后在调用containsKey(key)前,线程B执行了put(key,null)操作,那么线程A再调用containsKey(key)验证是否存在key,那么这时会发现key是存在的,但其实对于线程A而已key是不存在的,就存在数据两义性问题。所以ConcurrentHashMap不允许value为null。
    public static void main(String[] args) throws InterruptedException {
        final Map hashMap = new HashMap();
        String key = "hashKey";
        new Thread(() -> {
            final Object o = hashMap.get(key);
            if (o == null) {
                if (hashMap.containsKey(key)) {
                    System.out.println("hashMap 存在key为" + key + " value为null的键值");
                } else {
                    System.out.println("hashMap 不存在key为" + key + " value为null的键值");
                }
            }
        }).start();
        Thread.sleep(100);
        hashMap.put(key, null);
    }

没有结尾硬加的结尾