当前位置: 首页 > news >正文

多线程:三大集合类

在Java开发中,HashTable、HashMap和ConcurrentHashMap是三个常用的键值对存储集合,它们在面试和实际开发中都扮演着重要角色。

1.基本概念

HashTable
HashTable是Java早期(JDK 1.0)提供的键值对存储结构,它是一个线程安全的哈希表实现。


// HashTable基本用法
Hashtable<String, Integer> hashtable = new Hashtable<>();
hashtable.put("key1", 1);
hashtable.put("key2", 2);
Integer value = hashtable.get("key1");

HashMap
HashMap在JDK 1.2中引入,提供了与HashTable类似的功能,但不是线程安全的,性能更好。


// HashMap基本用法
HashMap<String, Integer> hashMap = new HashMap<>();
hashMap.put("key1", 1);
hashMap.put("key2", 2);
Integer value = hashMap.get("key1");

ConcurrentHashMap
ConcurrentHashMap在JDK 1.5中引入,旨在提供线程安全且高性能的哈希表实现。


// ConcurrentHashMap基本用法
ConcurrentHashMap<String, Integer> concurrentMap = new ConcurrentHashMap<>();
concurrentMap.put("key1", 1);
concurrentMap.put("key2", 2);
Integer value = concurrentMap.get("key1");

2. 线程安全性对比

HashTable的线程安全实现
HashTable通过在所有公共方法上添加`synchronized`关键字来实现线程安全:


// HashTable的同步机制(简化版)
public synchronized V put(K key, V value) {
// 实现逻辑
}

public synchronized V get(Object key) {
// 实现逻辑
}

这种粗粒度的锁机制导致性能瓶颈,因为整个表被锁定,同一时间只能有一个线程操作。

HashMap的线程不安全特性
HashMap不是线程安全的,在多线程环境下可能出现问题:


// 多线程下HashMap的问题示例
public class HashMapThreadUnsafe {
public static void main(String[] args) throws InterruptedException {
Map<String, Integer> map = new HashMap<>();

Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
map.put("key" + i, i);
}
});

Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
map.put("key" + i, i * 2);
}
});

t1.start();
t2.start();
t1.join();
t2.join();

// 可能出现各种异常或数据不一致
}
}

ConcurrentHashMap的线程安全实现
ConcurrentHashMap使用更精细的锁机制:

JDK 1.7及之前:使用分段锁(Segment)

// JDK 1.7的分段锁概念
static final class Segment<K,V> extends ReentrantLock {
// 每个Segment管理一部分哈希桶
}

JDK 1.8及之后:使用CAS + synchronized

// JDK 1.8使用Node和CAS
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
volatile V val;
volatile Node<K,V> next;
}

3. 性能分析

 单线程性能
- HashMap:性能最佳,无同步开销
- ConcurrentHashMap:次之,有少量CAS开销
- HashTable:性能最差,同步开销大

多线程性能
在多线程环境下,性能对比发生显著变化:


// 性能测试示例
public class MapPerformanceTest {
private static final int THREAD_COUNT = 10;
private static final int OPERATION_COUNT = 100000;

public static void main(String[] args) throws InterruptedException {
// HashMap(线程不安全,仅作对比)
// Map<String, Integer> map = new HashMap<>();

// HashTable性能测试
Map<String, Integer> hashtable = new Hashtable<>();
testPerformance(hashtable, "Hashtable");

// ConcurrentHashMap性能测试
Map<String, Integer> concurrentMap = new ConcurrentHashMap<>();
testPerformance(concurrentMap, "ConcurrentHashMap");
}

private static void testPerformance(Map<String, Integer> map, String name) 
throws InterruptedException {
long startTime = System.currentTimeMillis();

List<Thread> threads = new ArrayList<>();
for (int i = 0; i < THREAD_COUNT; i++) {
Thread thread = new Thread(() -> {
for (int j = 0; j < OPERATION_COUNT; j++) {
String key = "key-" + Thread.currentThread().getId() + "-" + j;
map.put(key, j);
map.get(key);
}
});
threads.add(thread);
thread.start();
}

for (Thread thread : threads) {
thread.join();
}

long endTime = System.currentTimeMillis();
System.out.println(name + " 耗时: " + (endTime - startTime) + "ms");
}
}

测试结果通常显示:
- ConcurrentHashMap在多线程环境下性能明显优于HashTable
- 随着线程数增加,性能差距更加明显

4. 空值处理差异

HashMap
允许null键和null值:

HashMap<String, String> map = new HashMap<>();
map.put(null, "null key");      // 允许
map.put("key", null);           // 允许

HashTable
不允许null键或null值:

Hashtable<String, String> table = new Hashtable<>();
table.put(null, "value");       // 抛出NullPointerException
table.put("key", null);         // 抛出NullPointerException

ConcurrentHashMap
不允许null键或null值:

ConcurrentHashMap<String, String> concurrentMap = new ConcurrentHashMap<>();
concurrentMap.put(null, "value"); // 抛出NullPointerException
concurrentMap.put("key", null);   // 抛出NullPointerException

设计原因:
- HashTable和ConcurrentHashMap在并发环境下,无法明确区分"键不存在"和"键对应的值为null"
- HashMap在单线程环境下没有这个问题

5. 内部实现细节

HashMap的内部结构(JDK 1.8+)

// 数组 + 链表/红黑树
transient Node<K,V>[] table;

static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
V value;
Node<K,V> next;
}

当链表长度超过8且数组长度大于64时,链表转换为红黑树。

 ConcurrentHashMap的内部结构(JDK 1.8+)

// 使用volatile和CAS保证可见性和原子性
transient volatile Node<K,V>[] table;

static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
volatile V val;
volatile Node<K,V> next;
}

6. 扩容机制对比

HashMap扩容
- 默认初始容量:16
- 负载因子:0.75
- 扩容:容量翻倍

ConcurrentHashMap扩容
- 更复杂的扩容机制,支持并发扩容
- 多个线程可以协助完成扩容过程

7. 使用场景建议

使用HashMap的场景
- 单线程环境
- 不需要线程安全
- 需要最高性能
- 需要存储null键或null值


// 缓存实现示例(单线程)
public class SimpleCache<K, V> {
private final Map<K, V> cache = new HashMap<>();

public void put(K key, V value) {
cache.put(key, value);
}

public V get(K key) {
return cache.get(key);
}
}

使用ConcurrentHashMap的场景
- 高并发环境
- 需要线程安全
- 对性能要求较高
- 不需要存储null值


// 线程安全的缓存实现
public class ConcurrentCache<K, V> {
private final ConcurrentHashMap<K, V> cache = new ConcurrentHashMap<>();

public void put(K key, V value) {
cache.put(key, value);
}

public V get(K key) {
return cache.get(key);
}

// 使用computeIfAbsent实现原子操作
public V computeIfAbsent(K key, Function<K, V> mappingFunction) {
return cache.computeIfAbsent(key, mappingFunction);
}
}

使用HashTable的场景
- 遗留系统维护
- 需要与旧代码兼容
- 并发要求不高的场景

1. 单线程环境:优先使用HashMap
2. 高并发环境:优先使用ConcurrentHashMap
3. 新项目:避免使用HashTable
4. 缓存null值:考虑使用Optional包装

http://www.dtcms.com/a/453172.html

相关文章:

  • html css js网页制作成品——化妆品html+css+js (7页)附源码
  • OpenAI战略转型深度解析:从模型提供商到全栈生态构建者的野望
  • 怎么做网站自动采集数据hao123设为主页官网下载
  • 重庆孝爱之家网站建设网站单页设计
  • 13、Linux 基本权限
  • k8s-ingress控制器
  • 【AI】深入 LangChain 生态:核心包架构解析
  • CodeBuddy Code + 腾讯混元打造“AI识菜通“
  • 记录踩过的坑-金蝶云·苍穹平台-杂七杂八
  • 【嵌入式原理系列-第11篇】半导体电子传输与PN结工作原理浅析
  • 磁力链接 网站怎么做的做网站多少钱西宁君博专注
  • 苹果RL4HS框架的技术原理
  • 在哪网站开发软件发视频的网址网址是什么?
  • 第74篇:AI+教育:个性化学习、智能辅导与虚拟教师
  • 2025 AI 落地元年:从技术突破到行业重构的实践图景
  • 《每日AI-人工智能-编程日报》--2025年10月7日
  • 公司销售泄密公司资料如何管控?信企卫文件加密软件深度分析
  • .NET+AI: (微家的AI开发框架)什么是内核记忆(Kernel Memory)?
  • 版本控制器 git(2)--- git 基本操作
  • 数字信号处理 第六章(IIR数字滤波器设计)
  • 辽宁专业网页设计免费建站正规seo服务商
  • 西安将军山网站建设wordpress评论模板怎么改
  • 抽象类定义
  • 基于sprigboot的农贸市场摊位管理系统(源码+论文+部署+安装)
  • 基于Flink的AB测试系统实现:从理论到生产实践
  • 开源 C++ QT QML 开发(八)自定义控件--圆环
  • CTF攻防世界WEB精选基础入门:backup
  • 建设信用卡积分网站网站备案掉了
  • 免杀技术(高级中的基础手法)之PE扩大节注入ShellCode
  • C#自动化程序界面