网站快备,百度无广告搜索引擎,网店运营推广,wordpress 目录 伪静态一、先明确核心定位HashMap#xff1a;Java 集合框架中非线程安全的哈希表实现#xff0c;追求极致的单线程性能#xff0c;是日常开发中最常用的键值对存储容器。Hashtable#xff1a;Java 早期#xff08;JDK 1.0#xff09;提供的线程安全的哈希表实现#xff0c;设计…一、先明确核心定位HashMapJava 集合框架中非线程安全的哈希表实现追求极致的单线程性能是日常开发中最常用的键值对存储容器。HashtableJava 早期JDK 1.0提供的线程安全的哈希表实现设计较为简单粗暴目前已基本被ConcurrentHashMap替代。二、HashMap 与 Hashtable 详细区别我会从核心维度拆解每个维度都说明具体差异和背后的原因维度HashMapHashtable1. 线程安全性非线程安全线程安全但实现方式极 “笨重”2. 锁机制无锁所有操作均不做同步处理所有方法put/get/remove/size 等都用synchronized修饰本质是全表加锁- 任何线程操作 Hashtable 时都会锁住整个哈希表- 即使两个线程操作不同的 key也会互相阻塞并发性能极差。3. 空值null支持允许- key 可以为 null仅允许 1 个因为 hash 值固定为 0- value 可以为 null多个。禁止- 无论是 key 还是 value传入 null 都会直接抛出NullPointerException- 原因Hashtable 设计时认为 null 会导致歧义且同步场景下判空会增加复杂度。4. 底层实现 / 结构JDK 1.8 后数组 链表 红黑树链表长度≥8 且数组长度≥64 时转红黑树JDK 1.7数组 链表。始终是数组 链表从未支持红黑树优化底层数组默认大小、扩容阈值等也有差异见下文。5. 哈希计算方式JDK 1.8 优化了哈希算法key.hashCode () → 扰动函数减少哈希冲突 →(n - 1) hash取模高效。直接使用key.hashCode() % table.length取模取模运算效率低于位运算无扰动函数哈希冲突概率更高。6. 初始容量与扩容- 初始容量默认 16- 扩容阈值默认负载因子 0.75当size 容量 * 负载因子时扩容- 扩容规则容量翻倍×2- 支持手动指定初始容量会向上取整为 2 的幂。- 初始容量默认 11- 扩容阈值默认负载因子 0.75- 扩容规则容量变为2 * 原容量 1非 2 的幂进一步降低取模效率- 手动指定的初始容量不会取整直接使用。7. 迭代器特性快速失败fail-fast迭代过程中如果其他线程修改了 HashMap 结构增 / 删节点迭代器会立即抛出ConcurrentModificationException注意单线程下如果迭代时自己修改如 remove也会触发。枚举器Enumeration是快速失败的如果通过keySet().iterator()获取迭代器同样是 fail-fast 特性。8. 继承体系继承AbstractMap类实现Map接口。继承Dictionary类已废弃实现Map接口Dictionary是早期的键值对容器设计上不如AbstractMap优雅。9. 性能表现单线程下性能极高无锁开销哈希计算和扩容更高效。无论单线程 / 多线程性能都差- 单线程全表锁无意义还增加同步开销- 多线程全表锁导致并发度极低线程竞争激烈时性能暴跌。10. 使用场景单线程 / 低并发场景如方法内局部变量、单例中的静态变量且仅单线程操作。几乎无推荐场景- 线程安全场景优先用ConcurrentHashMap并发性能高- 低并发线程安全场景也可使用Collections.synchronizedMap(new HashMap())比 Hashtable 灵活。三、补充Hashtable 被淘汰的核心原因并发性能极差全表锁导致多线程下几乎是串行执行而ConcurrentHashMap仅锁单个桶并发度提升数十倍。设计老旧基于废弃的Dictionary类哈希计算、扩容规则等都未做优化性能远不如 HashMap更不如 ConcurrentHashMap。功能限制不支持 null 值使用场景被进一步压缩。四、代码示例直观感受差异1. 空值支持差异public class HashMapVsHashtable { public static void main(String[] args) { // HashMap 支持 null key/value HashMapString, String hashMap new HashMap(); hashMap.put(null, nullKey); hashMap.put(key1, null); System.out.println(HashMap null key: hashMap.get(null)); // 输出nullKey System.out.println(HashMap null value: hashMap.get(key1)); // 输出null // Hashtable 不支持 null抛 NullPointerException HashtableString, String hashtable new Hashtable(); try { hashtable.put(null, nullKey); // 直接抛异常 } catch (NullPointerException e) { System.out.println(Hashtable 不支持 null key); } try { hashtable.put(key1, null); // 直接抛异常 } catch (NullPointerException e) { System.out.println(Hashtable 不支持 null value); } } }2. 线程安全差异多线程操作import java.util.HashMap; import java.util.Hashtable; public class ThreadSafetyTest { private static HashMapString, Integer hashMap new HashMap(); private static HashtableString, Integer hashtable new Hashtable(); public static void main(String[] args) throws InterruptedException { // 测试 HashMap 线程不安全多线程put可能导致死循环/数据丢失 Runnable hashMapTask () - { for (int i 0; i 1000; i) { hashMap.put(Thread.currentThread().getName() i, i); } }; // 测试 Hashtable 线程安全不会出现数据错乱但并发慢 Runnable hashtableTask () - { for (int i 0; i 1000; i) { hashtable.put(Thread.currentThread().getName() i, i); } }; Thread t1 new Thread(hashMapTask); Thread t2 new Thread(hashMapTask); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println(HashMap 最终大小可能≠2000 hashMap.size()); // 数据丢失/错乱 Thread t3 new Thread(hashtableTask); Thread t4 new Thread(hashtableTask); t3.start(); t4.start(); t3.join(); t4.join(); System.out.println(Hashtable 最终大小一定2000 hashtable.size()); // 数据完整 } }总结核心差异HashMap非线程安全、支持 null、单线程性能高Hashtable线程安全全表锁、不支持 null、并发性能极差。使用选择单线程用HashMap多线程安全场景优先用ConcurrentHashMap而非 Hashtable。设计层面Hashtable 是早期设计的产物哈希计算、扩容、锁机制均无优化现已被淘汰仅作历史知识点了解即可。