为什么 ConcurrentHashMap 阻止 null 键和 null 值?

发布于 2024-07-16 06:36:53 字数 473 浏览 3 评论 0原文

ConcurrentHashMap 的 JavaDoc 说的是:

Hashtable 类似,但与 HashMap 不同,此类不允许允许将 null 用作键或值。

我的问题:为什么?

第二个问题:为什么 Hashtable 不允许 null?

我使用了很多 HashMap 来存储数据。 但是,当更改为 ConcurrentHashMap 时,由于 NullPointerExceptions,我多次遇到麻烦。

The JavaDoc of ConcurrentHashMap says this:

Like Hashtable but unlike HashMap, this class does not allow null 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

酒中人 2024-07-23 06:36:53

来自 ConcurrentHashMap 的作者本人 (Doug莉亚)

ConcurrentMaps 中不允许使用 null 的主要原因
(ConcurrentHashMaps, ConcurrentSkipListMaps) 的歧义在于
在非并发地图中可能只是勉强可以忍受不能
容纳。 主要的一点是,如果 map.get(key) 返回 null,那么您
无法检测键是否显式映射到 null 与键不是
映射。 在非并发地图中,您可以通过以下方式检查
map.contains(key),但在并发情况下,地图可能已更改
通话之间。

From the author of ConcurrentHashMap himself (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.

猫性小仙女 2024-07-23 06:36:53

我相信,至少在某种程度上,它允许您将 containsKeyget 组合到一个调用中。 如果映射可以保存 null,则无法判断 get 是否返回 null,因为没有该值的键,或者只是因为该值为 null。

为什么这是一个问题? 因为没有安全的方法可以让你自己做到这一点。 采用以下代码:

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

由于 m 是并发映射,因此在 containsKeyget 调用之间可能会删除键 k,从而导致此代码段返回一个从未出现在表中的 null,而不是所需的 KeyNotPresentException。

通常您可以通过同步来解决这个问题,但是使用并发映射当然是行不通的。 因此 get 的签名必须更改,而以向后兼容的方式做到这一点的唯一方法是防止用户首先插入空值,并继续将其用作占位符“找不到钥匙”。

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();
}

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".

三生路 2024-07-23 06:36:53

Josh Bloch 设计了 ​​HashMap; Doug Lea 设计了ConcurrentHashMap。 我希望这不是诽谤。 实际上,我认为问题在于空值通常需要包装,以便真正的空值可以代表未初始化。 如果客户端代码需要空值,那么它可以支付包装空值本身的(诚然很小)成本。

Josh Bloch designed HashMap; Doug Lea designed ConcurrentHashMap. 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.

如若梦似彩虹 2024-07-23 06:36:53

您无法在 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.

各空 2024-07-23 06:36:53

我猜下面的 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 to Hashtable. And as Hashtable does not allow null keys and values..

烟燃烟灭 2024-07-23 06:36:53

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.

孤蝉 2024-07-23 06:36:53

我认为禁止空值不是一个正确的选择。
在很多情况下,我们确实希望将一个具有空值的键放入并发映射中。 但是,通过使用 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文