ConcurrentHashMap和HashTable小细节

内容总结于敖丙:

https://mp.weixin.qq.com/s/AixdbEiXf3KfE724kg2YIw

多线程下能够代替hashmap的有哪些?

三种

  • 使用Collections.synchonizedMap()去把一个map类型转换成一个安全的map集合(所有操作加互斥锁)
  • 使用hashtable
  • 使用ConcurrentHashMap

但由于前两者都是单纯的给所有操作加上锁来保证并发安全,效率并不高。

咱一般使用第三种.

Collections.synchonizedMap()如何实现线程安全?

内部维护了一个map对象(也就是我们调用工具类的时候传进来的),然后自己也维护了一个互斥锁,对创建出来的map集合的所有操作都会加上锁。

那HashTable呢?

hashtable用的人很少,其实现其实也是给所有方法加上锁

除了线程安全,HashTable和HashMap有啥区别呢?

HashTable put进去的key和value都不能为null,而hashmap可以。

为啥HashTable不能呢(ConcurrentHashMap也不行哈),因为它们都是用于并发的,但如果能为null的话,并不能知道到底是没有这个key,还是这个key对应的值为null,因为在get之后,并不能再一次用containKey去验证它(并发情况中间可能都进行了多次操作了)

而hashmap本来就是服务于单线程的,所以不行就不行拉,破罐子破摔。

ConcurrentHashMap的数据结构是咋样的,为啥并发度这么高?

1.7 segment数组+HashEntry,也是数组+链表的形式,只不过由于segment这个东西的存在,实现了分段锁的机制,我理解的是在hashtable的样子上加了一个【维度】,即把每个segment看作是一个hashtable,每次上锁只用锁上一个segement,其他的segment正常使用。比如有16个segment,就同时支持16个线程的并发。(要注意个别方法还是会锁住整个表如size)

还有不同的是这里的HashEntry的value字段是加上了volatile关键字的,保证了取节点时的可见性。同时也只有value字段是没有加上final修饰的,这说明修改节点可以直接修改,但是因为next是被final修饰的,删除节点只能把前续节点全部复制,所以remove比较耗时。

put操作呢是先hash,找到位置之后自旋获取锁,自旋到一定次数转化为阻塞锁。获取到锁之后再次hash得到位置,放置节点,判断是否初始化、扩容。

get操作也是两次hash找位置,但是特点呢是全程无锁,因为上面提到了使用volatile 保证了可见性。

也正式因为volatile,使用ConcurrentHashMap可要小心哦比如并发情况的  map.put(1,map.get(1)+1) 是会出错的,因为volatile没保证原子性。

1.8 抛弃了笨重的segment,采用CAS和Synchronized来保证安全性。

面试的时候可能会牵扯出CAS,ABA,Synchronized,锁升级等等,任重道远呀。

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值