Hashtable 与 ConcurrentHashMap 总结

上一篇简单介绍了众多map中的HashMap ,最后提及HashMap的最大缺点就是线程不安全。今天我们介绍两种线程安全的map容器,看它们是如何来解决线程安全的问题。

问题:HashMap为什么线程不安全?

jdk1.7时会出现环形链表导致死循环 --》元凶是在扩容时进行元素插入使用的是头插法(在1.8后使用尾插法解决了这个问题)

jdk1.8时会出现元素覆盖的情况 --》当线程A,B同时进行put操作 当判断完hash碰撞之后假如此时链表为null 会直接赋值,但此时线程A时间片执行完挂起 ,线程B在时间片内完成赋值操作,之后线程A继续执行 会将B直接覆盖 (可理解为链表头元素丢失了

接下来我们引来一个今天第一个不常见的主角 Hashtable 这个小写看着确实很别扭,为什么说它不常见呢,因为平时很少使用它。至于为什么很少使用,我们后续再说先扒扒它的结构

来让我们详细想想好想根HashMap一样呀! 这货应该也是数组+链表的结构

我们来看看它上面的put 和 get 方法 一看便知真想 这两个都是同步方法,使用了synchronized 关键字相当于锁住了Hashtable的对象,Hashtable 就是使用了这种排它锁粗暴的解决了线程安全问题。但是也带来了不支持并发操作的问题。

接下来我们来介绍另一个主角 ConcurrentHashMap 下简称(Cmap)

它也是线程安全的map容器,它比Hashtable强在哪里呢? 

先说结论:它能支持并发操作。并且在1.8中 Hashtable 一直是链表结构,而我们的Cmap在满足链表长度后会转化为红黑树解决链表过长的问题。

那它为什么能支持并发呢? 

(jdk1.7还没下载好 原谅我偷懒不贴图了)1.7时代jdk实现Cmap的方案是分段锁,何为分段锁呢,就是先做两次散列把数据分段之后将分段数据存入特殊Hashtable(segment)的数组 因为每个Hashtable都支持自己段内的线程安全操作,所以可以支撑数组长度的并发操作。另外Cmap中使用了volatile关键字,保证了读取元素的时候各个线程可见。

1.8时代就采取了不同的方案,1.8中Cmap所采用的数据结构根我们之前介绍的HashMap一致。

那它是如何实现线程安全的呢 ? 让我们来看看

jdk1.8为什么着么做呢? 首先cas操作肯定要比锁要轻量级的多,而在同样使用synchronized的地方,1.7是锁住了segment整个Hashtable 而 1.8只是锁住了更细级别的链表。而且可以随着扩容增加并发量!可见1.8的优化是多棒!!

总结就到这里欢迎大家指正问题 !!  与君共勉

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值