[英]Why does ConcurrentHashMap prevent null keys and values?
ConcurrentHashMap
的 JavaDoc 是這樣說的:
像
Hashtable
但不同於HashMap
,這個類不允許null
用作鍵或值。
我的問題:為什么?
第二個問題:為什么Hashtable
不允許為空?
我使用了很多 HashMap 來存儲數據。 但是當更改為ConcurrentHashMap
時,由於 NullPointerExceptions,我遇到了幾次麻煩。
來自ConcurrentHashMap
的作者本人(Doug Lea) :
ConcurrentMaps(ConcurrentHashMaps、ConcurrentSkipListMaps)中不允許空值的主要原因是無法適應在非並發映射中幾乎不能容忍的歧義。 主要的一個是,如果
map.get(key)
返回null
,您無法檢測鍵是否顯式映射到null
與鍵未映射。 在非並發映射中,您可以通過map.contains(key)
檢查這一點,但在並發映射中,映射可能在調用之間發生了變化。
我相信這是,至少部分,讓你結合containsKey
並get
到一個單一的電話。 如果映射可以保存空值,則無法判斷get
是否返回空值是因為該值沒有鍵,或者僅僅是因為該值是空值。
為什么這是一個問題? 因為沒有安全的方法可以自己做到這一點。 取以下代碼:
if (m.containsKey(k)) {
return m.get(k);
} else {
throw new KeyNotPresentException();
}
由於m
是並發映射,因此鍵 k 可能會在containsKey
和get
調用之間被刪除,從而導致此代碼段返回一個從未出現在表中的空值,而不是所需的KeyNotPresentException
。
通常你會通過同步來解決這個問題,但是使用並發映射當然是行不通的。 因此get
的簽名必須改變,以向后兼容的方式做到這一點的唯一方法是首先防止用戶插入空值,並繼續使用它作為“未找到密鑰”的占位符。
Josh Bloch 設計了HashMap
; Doug Lea 設計了ConcurrentHashMap
。 我希望這不是誹謗。 實際上我認為問題在於空值通常需要包裝,以便真正的空值可以代表未初始化。 如果客戶端代碼需要空值,那么它可以支付包裝空值本身的(不可否認的小)成本。
您不能在 null 上同步。
編輯:在這種情況下,這並不是為什么。 我最初認為針對並發更新鎖定事物或以其他方式使用對象監視器來檢測某些內容是否被修改是很有趣的事情,但是在檢查源代碼時發現我錯了 - 他們使用基於哈希的位掩碼。
在那種情況下,我懷疑他們這樣做是為了復制 Hashtable,我懷疑 Hashtable 這樣做是因為在關系數據庫世界中,null != null,因此使用 null 作為鍵沒有意義。
ConcurrentHashMap 是線程安全的。 我相信不允許空鍵和值是確保它是線程安全的一部分。
我想 API 文檔的以下片段給出了一個很好的提示:“此類在依賴其線程安全但不依賴其同步細節的程序中與 Hashtable 完全可互操作。”
他們可能只是想讓ConcurrentHashMap
與Hashtable
完全兼容/可互換。 由於Hashtable
不允許空鍵和值..
我認為不允許空值是一個正確的選擇。 在許多情況下,我們確實希望將具有空值的鍵放入並發映射中。 但是,通過使用 ConcurrentHashMap,我們無法做到這一點。 我建議即將發布的 JDK 版本可以支持這一點。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.