Java 为什么 ConcurrentHashMap 防止空键和值?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/698638/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 18:28:41  来源:igfitidea点击:

Why does ConcurrentHashMap prevent null keys and values?

javaconcurrenthashmap

提问by Marcel

The JavaDoc of ConcurrentHashMapsays this:

的 JavaDoc 是这样ConcurrentHashMap说的:

Like Hashtablebut unlike HashMap, this class does notallow nullto be used as a key or value.

类似Hashtable但不同HashMap,这个类就不会允许null用作键或值。

My question: Why?

我的问题:为什么?

2nd question: Why doesn't Hashtableallow null?

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

I've used a lot of HashMaps for storing data. But when changing to ConcurrentHashMapI got several times into trouble because of NullPointerExceptions.

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

采纳答案by Bruno

From the author of ConcurrentHashMaphimself (Doug Lea):

来自ConcurrentHashMap他本人(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 nullvs 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.

ConcurrentMaps(ConcurrentHashMaps、ConcurrentSkipListMaps)中不允许空值的主要原因是无法适应在非并发映射中几乎无法容忍的歧义。主要的一个是,如果map.get(key)返回null,您无法检测键是否显式映射到null键未映射。在非并发映射中,您可以通过 来检查这一点 map.contains(key),但在并发映射中,映射可能在调用之间发生了变化。

回答by Kevin Crowell

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 是线程安全的。我相信不允许空键和值是确保它是线程安全的一部分。

回答by Paul Tomblin

You can't synchronize on a null.

您不能在 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 codeit 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.

在那种情况下,我怀疑他们这样做是为了复制 Hashtable,我怀疑 Hashtable 这样做是因为在关系数据库世界中,null != null,因此使用 null 作为键没有意义。

回答by Tobias Müller

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

我想 API 文档的以下片段给出了一个很好的提示:“此类在依赖其线程安全但不依赖其同步细节的程序中与 Hashtable 完全可互操作。”

They probably just wanted to make ConcurrentHashMapfully compatible/interchangeable to Hashtable. And as Hashtabledoes not allow null keys and values..

他们可能只是想ConcurrentHashMap完全兼容/互换Hashtable。并且Hashtable不允许空键和值..

回答by Tom Hawtin - tackline

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.

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

回答by Alice Purcell

I believe it is, at least in part, to allow you to combine containsKeyand getinto a single call. If the map can hold nulls, there is no way to tell if getis returning a null because there was no key for that value, or just because the value was null.

我相信它至少部分是为了让您能够将containsKey和组合get成一个单一的调用。如果映射可以保存空值,则无法判断是否get返回空值是因为该值没有键,或者仅仅是因为该值是空值。

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 mis a concurrent map, key k may be deleted between the containsKeyand getcalls, causing this snippet to return a null that was never in the table, rather than the desired KeyNotPresentException.

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

Normally you would solve that by synchronizing, but with a concurrent map that of course won't work. Hence the signature for gethad 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".

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

回答by yinhaomin

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.

我认为不允许空值是一个正确的选择。在许多情况下,我们确实希望将具有空值的键放入并发映射中。但是,通过使用 ConcurrentHashMap,我们无法做到这一点。我建议即将发布的 JDK 版本可以支持这一点。