【面试高频】HashMap\HashTable\ConcurrentHashMap之间的区别

多线程环境中对于集合类的使用需求

在多线程环境中使用集合类时,需要考虑线程安全问题。此时那些常见的集合类例如ArrayList,LinkedList,HashMap等就不能满足要求了。

此时有两个解决方法:1、直接手动加锁来保证线程安全。比如多个线程去修改ArrayList就可能会有线程安全问题,就可以给修改操作加锁;2、标准库中提供了一些线程安全的集合类。例如:如果需要使用ArrayList,可以使用Vector来代替。

而HashTable正是HashMap的代替方案。

HashTable的解决方案

HashTable是针对整个哈希表进行加锁,任何增删查改的操作,都会触发加锁

向哈希表中插入元素的操作:根据key计算hash值,找到对应的数组下标。然后把这个新的元素挂到对应下标的链表上。

如果此时有两个线程,插入了两个元素。线程一插入的元素对应在下标1的链表上,线程二插入的元素对应在下标2的链表上。此时不存在线程安全问题(两个线程修改不同变量,所以没有线程安全问题)。

此时,虽然两个操作没有线程安全问题,但是由于锁是加在整个哈希表上的,仍然会针对同一个对象(即同一个哈希表)产生锁竞争,产生阻塞等待

实际上仔细思考,发现其实也没必要加锁过于频繁。而且因为对于整个哈希表进行加锁会导致锁的粒度过大。

此时的优化方案就是ConcurrentHashMap集合类

ConcurrentHashMap提供的解决方案

ConcurrentHashMap不是只有一把锁,而是每个链表都有一把锁

每次进行操作,都是针对对应链表的锁进行加锁,操作不同链表就是针对不同的锁加锁,不会有锁冲突。

这就导致大部分加锁操作实际上没有锁冲突,此时这里的加锁操作的开销就微乎其微了

三者的区别

HashTable和ConcurrentHashMap是HashMap的线程安全的集合类。

而 HashTable和ConcurrentHashMap除了上述最大的区别外——加锁的粒度不同,还有以下两个区别:

1、后者更充分地利用了CAS机制——>无锁编程。

有的操作,比如获取/更新元素个数,就可以直接使用CAS完成,不必加锁了

2、优化了扩容策略

对于HashTable来说,如果元素太多,就会涉及扩容。扩容需要重新申请内存空间,将元素从旧的哈希表上删除,插入到新的哈希表上。

如果本身元素非常多,搬运一次成本就很高。会导致这一次操作非常卡顿

而后者策略,并不会试图一次性把所有的元素都搬运过去,而是每次搬运一部分

当put触发扩容,此时就会直接创建更大的内存空间,但是并不会直接把所有的元素都直接搬运过去,而是只搬运一小部分

此时就相当于同时存在两份hash表了。此时插入元素就直接往新表上插入,删除元素就从旧表上删除,查找元素时新表旧表都查

并且每次操作过程中,都会搬运一部分过去。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值