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

在很多java资料中,都有提到 ConcurrentHashmap HashMap和Hashtable都是key-value存储结构,但他们有一个不同点是 ConcurrentHashmap、Hashtable不支持key或者value为null,而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.

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

个人觉得这个解答还是很有道理的,也是解决了心头的一个疑惑,大牛们在设计时确实考虑的很多,在这里分享给大家。

类似的解答还有这个:
down vote
I believe it is, at least in part, to allow you to combine containsKey and get into a single call. If the map can hold nulls, there is no way to tell if get is returning a null because there was no key for that value, or just because the value was null.

Why is that a problem? Because there is no safe way to do that yourself. Take the following code:

if (m.containsKey(k)) {return m.get(k);
} else {throw new KeyNotPresentException();
}12345

Since m is a concurrent map, key k may be deleted between the containsKey and get calls, causing this snippet to return a null that was never in the table, rather than the desired KeyNotPresentException.

Normally you would solve that by synchronizing, but with a concurrent map that of course won’t work. Hence the signature for get had to change, and the only way to do that in a backwards-compatible way was to prevent the user inserting null values in the first place, and continue using that as a placeholder for “key not found”.

参考地址

其他辅助性(佐证性质)的理由见下文。(对于ConcurrentHashmap,我参考其他人的相关文章,觉得还有其他理由。)


ConcurrentHashmap中get方法为何不需要加锁同步

对于1.6,我们知道ConcurrentHashmap的get方法是没有加锁的,所以value不能为null刚好用上:newEntry对象是通过 new HashEntry(K k , V v, HashEntry next) 来创建的。如果另一个线程刚好new 这个对象时,当前线程来get它。因为没有同步,就可能会出现当前线程得到的newEntry对象是一个没有完全构造好的对象引用。

回想一下我们之前讨论的DCL的问题,这里也一样,没有锁同步的话,new 一个对象对于多线程看到这个对象的状态是没有保障的,这里同样有可能一个线程new这个对象的时候还没有执行完构造函数就被另一个线程得到这个对象引用。
所以才需要判断一下:if (v != null) 如果确实是一个不完整的对象,则使用锁的方式再次get一次。(来自参考文章1)

V get(Object key, int hash) {if (count != 0) { // read-volatile // ①HashEntry<K,V> e = getFirst(hash); while (e != null) {if (e.hash == hash && key.equals(e.key)) {V v = e.value;if (v != null)  // ② 注意这里return v;return readValueUnderLock(e); // recheck 见参考文章2}e = e.next;}}return null;
}

对于1.7,应该是通过UNSAFE.putOrderedObject(保证刚刚插入表头的节点被读取)来保证;对于1.8,采用CAS和synchronized保证并发一致,但似乎没有做对正在put数据的二次获取,未仔细研究,以上见参考文章3。

参考文章

http://www.cnblogs.com/yydcdut/p/3959815.html

https://segmentfault.com/q/1010000006669618

https://www.javadoop.com/post/hashmap#Java7%20ConcurrentHashMap

ConcurrentHashmap拾遗相关推荐

  1. 并发编程——ConcurrentHashMap#transfer() 扩容逐行分析

    并发编程--ConcurrentHashMap#transfer() 扩容逐行分析 </h1><div class="clear"></div> ...

  2. 【JAVA拾遗】Java8新特性合辑

    [JAVA拾遗]Java8新特性合辑 文章目录 [JAVA拾遗]Java8新特性合辑 0. 逼逼 [--/--]126 Lambda Expressions & Virtual Extensi ...

  3. 调试JDK源码-ConcurrentHashMap实现原理

    调试JDK源码-一步一步看HashMap怎么Hash和扩容 调试JDK源码-ConcurrentHashMap实现原理 调试JDK源码-HashSet实现原理 调试JDK源码-调试JDK源码-Hash ...

  4. WPF学习拾遗(二)TextBlock换行

    原文:WPF学习拾遗(二)TextBlock换行 下午在帮组里的同事解决一个小问题,为了以后方便,把就把它收集一下吧. 新建一个TextBlock作为最基础的一个控件,他所携带的功能相对于其他的控件要 ...

  5. 面试之Hashtable和ConcurrentHashMap

    那么要如何保证HashMap的线程安全呢? 方法有很多,比如使用Hashtable或者Collections.synchronizedMap,但是这两位选手都有一个共同的问题:性能.因为不管是读还是写 ...

  6. 深入研究ConcurrentHashMap 源码从7到8的变迁

    ConcurrentHashMap是线程安全且高效的HashMap 1 为什么要使用ConcurrentHashMap 线程不安全的HashMap HashMap是Java中最常用的一个Map类,性能 ...

  7. 【转】HashMap、TreeMap、Hashtable、HashSet和ConcurrentHashMap区别

    转自:http://blog.csdn.net/paincupid/article/details/47746341 一.HashMap和TreeMap区别 1.HashMap是基于散列表实现的,时间 ...

  8. Hashtable,HashMap,ConcurrentHashMap都是Map的实现类,它们在处理null值的存储上有细微的区别,下列哪些说法是正确的

    多选 Hashtable,HashMap,ConcurrentHashMap都是Map的实现类,它们在处理null值的存储上有细微的区别,下列哪些说法是正确的:答案在文末 A. Hashtable的K ...

  9. ConcurrentHashMap实现原理及源码分析

    ConcurrentHashMap是Java并发包中提供的一个线程安全且高效的HashMap实现(若对HashMap的实现原理还不甚了解,可参考我的另一篇文章HashMap实现原理及源码分析),Con ...

最新文章

  1. linux课程教学设计,《LINUX操作系统》课程整体教学设计.doc
  2. ASP.NET MVC学前篇之Ninject的初步了解
  3. 【深度学习的数学】接“2×3×1层带sigmoid激活函数的神经网络感知机对三角形平面的分类训练预测”,输出层加偏置b
  4. 利用python对微信云数据库_如何用python看看女神的微信百度云里面有啥?
  5. jstorm mysql_zookeeper,kafka,jstorm,memcached,mysql流式数据处理平台部署
  6. jpa中::::_项目学生:JPA标准查询
  7. OJ1021: 三个整数的最大值
  8. linux翻转字符串
  9. CSS3秘笈复习:第十一章
  10. Gephi教程-根据邻接矩阵构建复杂网络有向图
  11. 极客爱情 2.4 | 和程序员男友过节是这样的
  12. vs2010的Visual Assist X破解版安装
  13. 停车场管理系统 Java语言
  14. 清除Zabbix的历史记录
  15. php 文字合成图片,PHP图片和文字合成
  16. linux上怎么实现ssh免密登录
  17. windows server2012R2 apache+mod_wsgi+django
  18. c++读取文本中文乱码
  19. Android类似微信详细地址选择(高德地图)
  20. FTP服务器传输文件

热门文章

  1. 学习方法:如何在工作内外获得持续的技术成长
  2. 小程序如何分享到朋友圈,实现裂变
  3. 安徽省2016年c语言笔试,2016年安徽省计算机二级考试C语言(模拟试卷四)
  4. mysql 命令行 外键_MySQL基本命令行MySql外键设置详解
  5. java中image与tif图片的互转
  6. 工作分析文献综述_文献综述的写作步骤和注意事项
  7. “香港BT侵权判例”全球大争论
  8. 企业编程题实战(二)(解决牛客上用例运行与本地IDE不一致的问题)
  9. 【教学类-13-03】20221118《数字色块图5*7*8-A4横板-横切》(大班主题《》)
  10. 浙江大学计算机学院沈吕可晟,作品征集 | 敬廉崇洁,知诚讲信