🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇
HashTable HashMap ConcurrentHashMap
🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇
今日推荐歌曲: Airplane Mode -- Hayd 🎵🎵
前言
多线程环境使用哈希表
HashMap本身不是线程安全的.
在多线程环境下使用哈希表可以使用:
- Hashtable
- ConcurrentHashMap
- 这里会详细给大家讲述 这三种集合的特性和区别。
1) Hashtable
只是简单的把关键⽅法加上了synchronized关键字.
这相当于直接针对Hashtable对象本⾝加锁.
- 如果多线程访问同⼀个Hashtable就会直接造成锁冲突.
- size属性也是通过synchronized来控制同步,也是⽐较慢的.
- ⼀旦触发扩容,就由该线程完成整个扩容过程.这个过程会涉及到⼤量的元素拷⻉,效率会⾮常低.
一个 Hashtable 只有一把锁.
两个线程访问 Hashtable 中的任意数据都会出现锁竞争
2) ConcurrentHashMap
• 读操作没有加锁(但是使用了volatile保证从内存读取结果),只对写操作进行加锁。加锁的方式仍然是使用synchronized,但是不是锁整个对象,而是“锁桶”(用每个链表的头结点作为锁对象),大大降低了锁冲突的概率。
• 充分利用CAS特性。比如size属性通过CAS来更新,避免出现重量级锁的情况。
• 优化了扩容方式:化整为零
◦ 发现需要扩容的线程,只需要创建一个新的数组,同时只搬几个元素过去。
◦ 扩容期间,新老数组同时存在。
◦ 后续每个来操作ConcurrentHashMap的线程,都会参与搬家的过程。每个操作负责搬运一 小部分元素。
◦ 搬完最后⼀个元素再把⽼数组删掉.
◦ 这个期间,插⼊只往新数组加.
◦ 这个期间,查找需要同时查新数组和⽼数组
CurrentHlashMap 每个哈希桶都有一把锁.
只有两个线程访问的恰好是同一个哈希桶上的数据才出现锁冲突
3) 三者之间的区别 ⭐⭐⭐
这三种数据结构都用于存储键值对,但它们在实现上有一些区别:
-
HashTable:
- 基于哈希表实现。
- 线程安全,所有的操作都是同步的,性能较低。
- 不允许存储null键或值。
- 不建议使用,因为它是早期的实现,存在性能问题,通常被HashMap取代。
-
HashMap:
- 基于哈希表实现。
- 非线程安全,需要在多线程环境中手动处理同步问题。
- 允许存储null键和值。
- 在单线程环境下性能较好,但在多线程环境下需要额外的同步措施。
-
ConcurrentHashMap:
- 基于哈希表实现。
- 线程安全,采用了分段锁(Segment)的机制,多线程环境下性能较好。
- 允许存储null键和值。
- 适用于高并发的场景,比HashMap在多线程环境下更具性能优势。
主要区别在于线程安全性和性能表现:
- HashTable是线程安全的,但性能较差,因为它使用了全局锁。
- HashMap在单线程环境下性能较好,但在多线程环境下需要考虑同步问题。
- ConcurrentHashMap通过分段锁的方式实现了更好的并发性能,适用于高并发环境。
另外,值得一提的是,在Java 8之后,HashMap的实现发生了改变,引入了红黑树来解决哈希冲突,从而提高了查找、插入和删除操作的性能。ConcurrentHashMap也在后续版本中做了一些优化,提高了并发性能。
4)相关⾯试题
总结
三者区别再总结:
1. 线程安全性:
- Hashtable:使用synchronized关键字实现线程安全,所有操作都是同步的,但性能较差。
- HashMap:非线程安全,需要在多线程环境中手动处理同步问题。
- ConcurrentHashMap:采用分段锁(Segment)的机制实现线程安全,在多线程环境下性能较好。
2. 允许存储的元素:
- Hashtable和ConcurrentHashMap都不允许存储null键或值。
- HashMap允许存储null键和值。
3. 性能表现:
- Hashtable由于使用了全局锁,性能较差。
- HashMap在单线程环境下性能较好,但在多线程环境下需要额外的同步措施。
- ConcurrentHashMap在多线程环境下性能较好,采用分段锁的方式避免了全局锁的性能瓶颈,适用于高并发场景。
以上就是今天介绍的内容,边学边写博客也是对自己的巩固,后续会更新更多精彩博客!!