首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 程式設計入門

HashMap vs Hashtable:線程安全、Null 鍵值、性能與替代方案全對比

     編輯:Java 程式設計入門

核心差異對比表

維度HashMap (JDK 1.2+)Hashtable (JDK 1.0)
線程安全❌ 非線程安全✅ 所有公共方法 synchronized
Null Key✅ 允許一個 null key❌ 不允許 null key/value
Null Value✅ 允許多個 null value❌ 拋 NullPointerException
繼承體系實現 Map 介面,繼承 AbstractMap繼承 Dictionary,實現 Map
迭代器Fail-fast (檢測並發修改拋 CME)Enumerator (不保證 fail-fast)
性能高 (無鎖開銷)低 (全鎖粗粒度)
初始容量/擴容默認 16,2倍擴容 (冪次方)默認 11,2n+1 擴容 (質數)
Hash 計算JDK 8+ 擾動函數 + (n-1)&hash直接 key.hashCode()

為什麼 Hashtable 被淘汰?

  • 鎖粒度太粗:get/put/size 全部同步,高併發下嚴重爭用。
  • API 設計老舊:contains 歧義 (後分為 containsKey/containsValue)、elements() 返回 Enumeration。
  • 不支援 Null,限制使用場景。

線程安全 Map 的現代選擇

ConcurrentHashMap 核心原理 (JDK 1.8+)

  • 數組 Node[] table + 鏈表/紅黑樹 (鏈表長度 > 8 樹化)。
  • putVal:計算索引 → tab[i] == null → CAS 放入節點;否則 synchronized (首節點) 鎖住鏈表/樹頭節點操作。
  • size():LongAdder 思想,CounterCell[] 分段計數 + baseCount。
  • 擴容:多線程協助擴容 (transfer),每線程負責一段索引區間。

避坑指南

  1. HashMap 多線程導致死循環:JDK 7 擴容頭插法反轉鏈表形成環,JDK 8 改為尾插法但仍非線程安全 → 必須用 ConcurrentHashMap 或 Collections.synchronizedMap。
  2. 作為 Key 的對象必須不可變:覆寫 equals/hashCode,且字段 final (如 String、包裝類、自定義不可變類)。
  3. 初始容量預估:new HashMap((int)(expectedSize/0.75)+1) 避免多次擴容。
  4. 遍歷中刪除:用 Iterator.remove() 或 map.entrySet().removeIf() (Java 8+)。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
場景推薦類特點
高併發讀寫ConcurrentHashMapJDK 8+ CAS + synchronized (節點) + 分段鎖 → 細粒度,性能極佳
讀多寫少、需快照CopyOnWriteMap (Guava) / 自行包裝寫時復制,讀無鎖,適合配置表
需保持插入順序ConcurrentSkipListMap (有序) / LinkedHashMap + Collections.synchronizedMap前者並發有序,後者粗粒度鎖
簡單計數/緩存LongAdder / AtomicLong + ConcurrentHashMap原子計數器避免 Map 開銷