面试被问到HashTable, HashMap, ConcurrentHashMap 之间最大的区别是什么,我说名字不同,面试官让我回去等意向书

HashMap和HashTable、ConcurrentHashMap的区别

就线程安全来说,可分为两类

线程安全:HashTable, ConcurrentHashMap
线程不安全:HashMap

我们是如何知道这些类哪个线程安全,哪个不安全的呢?
通过查验原码可以发现:

HashMap的添加和删除,读等并没有加锁,在多线程下存在线程安全问题这里是引用
而其余两个类的方法都有加锁,以put方法为例
————————————————————————————————————————————
HashTable(put 方法):
在这里插入图片描述
——————————————————————————————————————————
ConcurrentHashMap的putVal方法:在这里插入图片描述

那么 HashTable和ConcurrentHashMap的区别又是什么呢?

HashTable和ConcurrentHashMap的区别

1.加锁方式不同:

HashTable:

根据上图HashTable的put方法可以发现,加锁是对整个方法加锁的,也就是说对this整个桶对象加锁:
在这里插入图片描述
这样虽然线程安全了,但带来的问题也显而易见:效率太低,因为每次添加删除都要加锁释放锁,且一次只能有一个线程添加一个元素或删除一个元素,换句话说就是锁冲突太高了。
那么为了提高效率,前面的大佬就把这个类优化了一下: ConcurrentHashMap 应运而生

ConcurrentHashMap :
我们可以观察发现:

这里是引用如果我们的添加删除对的是不同的桶操作,比如A添加,F也添加,这时就算不用加锁我们的线程也是安全的。那么我们只需要保证同一个桶的操作是线程安全的就可以了,那么就没必要全局加锁,可以给每个桶进行加锁,这样就可以大大提高效率,降低了锁冲突概率。如图所示:
在这里插入图片描述
——————————————————————————————————————————

其次 ConcurrentHashMap的读(get)操作并没有加锁,而是采用了volatile关键字来保证内存可见性。

在这里插入图片描述
HashTable的get:
在这里插入图片描述

扩容方式

HashTable

扩容主要流程:
在这里插入图片描述
这种扩容方式在数据量小的情况下,并无什么缺点,但当数据量非常大的时候,就会时不时出现某一次添加操作特别消耗时间,因为那一次正好是扩容的一次,由于大量的数据拷贝,为使得put’操作非常缓慢。

这时 ConcurrentHashMap扩容方式的优势就来了
ConcurrentHashMap:

主要流程:由于其的扩容原码过长,我就文字叙述一下:
ConcurrentHashMap的扩容方式,主要是为了弥补HashTable的扩容缺点,既然一次性拷贝使得某一次put时间过长,那么我们不如分多次拷贝。也就是当扩容时,创建一块新的比原来大的空间后,我们不一次性全拷贝过去,而是拷贝一部分,把时间均摊下来。在这期间,新旧数组同时存在,如果这时执行查询操作时,我们新旧两个表一起查询,删除操作也是新旧两个表查询来删除,插入新元素操作只往新空间插入元素,直到全部拷贝完,再把旧的桶扔掉。

3.size()的更新方式

HashTable的size更新也是在锁内进行的
而ConcurrentHashMap是利用CAS的特性来更新的,简单来说CAS可以无锁化的完成值调的增加减少操作,同时也线程安全,可以大大降低锁代理的性能消耗。

结尾

感谢阅读,如有错误欢迎指出!
在这里插入图片描述

  • 6
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值