多线程使用哈希表

本文介绍了在多线程环境中使用HashMap、Hashtable和ConcurrentHashMap的优缺点,重点强调了ConcurrentHashMap通过锁桶、CAS和优化扩容提高并发性能。
摘要由CSDN通过智能技术生成

一:HashMap

HashMap 本身不是线程安全的,在多线程的环境下,使用哈希表可以使用:Hashtable,ConcurrentHashMap.

二:Hashtable

Hashtable只是在每个方法上加上synchronized,相当于直接针对Hashtable对象加锁(this加锁),两个线程访问Hashtable中的任意数据都会出现锁竞争;
(1)如果多线程访问同一个Hashtable就会直接造成锁冲突
(2)size 属性也是通过synchronized来控制同步,也是比较慢的.
(3)一旦触发扩容,就由该线程完成整个扩容过程,这个过程会涉及到大量的元素拷贝,效率非常低.

三:ConcurrentHashMap

(1):读操作没有加锁(但使用了volatile保证从内存中读取结果),只对写操作加锁,加锁的方式仍然是用synchronized,但不是锁整个对象,而是"锁桶",(用每个链表的头节点作为锁对象),大大降低了锁冲突的概率.
在这里插入图片描述如果两个线程,针对不同的链表进行操作,是不会涉及到锁冲突的(本身,操作不同链表上的元素,也没有修改"公共变量",就不会涉及到线程安全)
收益是非常大的,一个hash表中,"桶"的数量 是非常多的,大量的操作,都不涉及到"锁冲突"了,synchronized就是偏向锁了

(2):充分利用CAS的特性,比如size属性通过CAS来来更新,避免出现重量级锁的情况.
(3)优化了扩容方法:化整为零.
扩容是非常重量的操作,平时的每次put,假设1us,触发扩容的这一次put,执行了1000ms,对于使用时有非常大的影响
ConcurrentHashMap会在扩容的时候,申请一个新的数组,这样就有两份空间,一份是扩容之前的空间,一份是扩容之后的空间,接下来每次进行hash表的基本操作,都会把一部分数据从旧空间搬运到新空间,而不是一次性搬完,
搬的过程中:
插入:插入到新的数组中;
删除:新的旧的都要删,
查找:新的旧的都要查找.
jdk 8之前,ConcurrentHashMap基于分段锁的方式来实现的:引入若干个锁对象,每个锁对象管理若干个Hash桶,相对于Hashtable是进化,但不如直接锁桶,代码写起来更复杂.

四:总结

HashMap:线程不安全,key允许为null
Hashtable :线程安全,使用synchronized 锁Hashtable对象,效率较低,key不允许为null
ConcurrentHashMap:线程安全,使用synchronized 锁每个链表头结点,锁冲突降低,充分利用CAS机制,优化了扩容方法,key不允许为null.

二级目录

三级目录

  • 13
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

十一.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值