为什么 ConcurrentHashMap 阻止 null 键和 null 值?
ConcurrentHashMap
的 JavaDoc 说的是:
与
Hashtable
类似,但与HashMap
不同,此类不允许允许将null
用作键或值。
我的问题:为什么?
第二个问题:为什么 Hashtable
不允许 null?
我使用了很多 HashMap 来存储数据。 但是,当更改为 ConcurrentHashMap 时,由于 NullPointerExceptions,我多次遇到麻烦。
The JavaDoc of ConcurrentHashMap
says this:
Like
Hashtable
but unlikeHashMap
, this class does not allownull
to be used as a key or value.
My question: Why?
2nd question: Why doesn't Hashtable
allow null?
I've used a lot of HashMaps for storing data. But when changing to ConcurrentHashMap
I got several times into trouble because of NullPointerExceptions.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
来自
ConcurrentHashMap
的作者本人 (Doug莉亚):From the author of
ConcurrentHashMap
himself (Doug Lea):我相信,至少在某种程度上,它允许您将
containsKey
和get
组合到一个调用中。 如果映射可以保存 null,则无法判断get
是否返回 null,因为没有该值的键,或者只是因为该值为 null。为什么这是一个问题? 因为没有安全的方法可以让你自己做到这一点。 采用以下代码:
由于
m
是并发映射,因此在containsKey
和get
调用之间可能会删除键 k,从而导致此代码段返回一个从未出现在表中的 null,而不是所需的 KeyNotPresentException。通常您可以通过同步来解决这个问题,但是使用并发映射当然是行不通的。 因此
get
的签名必须更改,而以向后兼容的方式做到这一点的唯一方法是防止用户首先插入空值,并继续将其用作占位符“找不到钥匙”。I believe it is, at least in part, to allow you to combine
containsKey
andget
into a single call. If the map can hold nulls, there is no way to tell ifget
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:
Since
m
is a concurrent map, key k may be deleted between thecontainsKey
andget
calls, causing this snippet to return a null that was never in the table, rather than the desiredKeyNotPresentException
.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".Josh Bloch 设计了 HashMap; Doug Lea 设计了ConcurrentHashMap。 我希望这不是诽谤。 实际上,我认为问题在于空值通常需要包装,以便真正的空值可以代表未初始化。 如果客户端代码需要空值,那么它可以支付包装空值本身的(诚然很小)成本。
Josh Bloch designed
HashMap
; Doug Lea designedConcurrentHashMap
. I hope that isn't libelous. Actually I think the problem is that nulls often require wrapping so that the real null can stand for uninitialized. If client code requires nulls then it can pay the (admittedly small) cost of wrapping nulls itself.您无法在 null 上进行同步。
编辑:在这种情况下这并不完全是原因。 我最初认为锁定事物以防止并发更新或以其他方式使用对象监视器来检测某些内容是否被修改是很奇特的事情,但在检查 源代码 看来我错了 - 他们使用基于位掩码的“段”进行锁定哈希值。
在这种情况下,我怀疑他们这样做是为了复制 Hashtable,我怀疑 Hashtable 这样做是因为在关系数据库世界中,null != null,所以使用 null 作为键没有任何意义。
You can't synchronize on a null.
Edit: This isn't exactly why in this case. I initially thought there was something fancy going on with locking things against concurrent updates or otherwise using the Object monitor to detect if something was modified, but upon examining the source code it appears I was wrong - they lock using a "segment" based on a bitmask of the hash.
In that case, I suspect they did it to copy Hashtable, and I suspect Hashtable did it because in the relational database world, null != null, so using a null as a key has no meaning.
我猜下面的 API 文档片段给出了很好的提示:
“在依赖其线程安全性但不依赖其同步细节的程序中,此类可与 Hashtable 完全互操作。”
他们可能只是想让 ConcurrentHashMap 与 Hashtable 完全兼容/可互换。 由于
Hashtable
不允许空键和值。I guess that the following snippet of the API documentation gives a good hint:
"This class is fully interoperable with Hashtable in programs that rely on its thread safety but not on its synchronization details."
They probably just wanted to make
ConcurrentHashMap
fully compatible/interchangeable toHashtable
. And asHashtable
does not allow null keys and values..ConcurrentHashMap 是线程安全的。 我相信不允许空键和值是确保线程安全的一部分。
ConcurrentHashMap is thread-safe. I believe that not allowing null keys and values was a part of making sure that it is thread-safe.
我认为禁止空值不是一个正确的选择。
在很多情况下,我们确实希望将一个具有空值的键放入并发映射中。 但是,通过使用 ConcurrentHashMap,我们无法做到这一点。
我建议即将推出的 JDK 版本可以支持这一点。
I don't think disallowing null value is a correct option.
In many cases, we do want do put a key with null value into the con-current map. However, by using ConcurrentHashMap, we cannot do that.
I suggest that the coming version of JDK can support that.