ConcurrentHashMap和HashMap的区别

1、两者的主要区别

  • 线程安全:HashMap 是线程不安全的,当出现多线程操作时,会出现安全隐患;而 ConcurrentHashMap 是线程安全的。
  • 并发操作:HashMap 不支持并发操作,没有同步方法,ConcurrentHashMap 支持并发操作,通过继承 ReentrantLock(JDK 1.7 重入锁)/CAS 和 synchronized (JDK 1.8 内置锁)来进行加锁(分段锁),每次需要加锁的操作锁住的是一个 segment,这样只要保证每个 Segment 是线程安全的,也就实现了全局的线程安全。
  • 引入版本:HashMap 是 JDK 1.2 引入的,ConcurrentHashMap 是 JDK 1.5 引入的
  • 允许空值:HashMap 的键和值允许使用空值,ConcurrentHashMap 如果使用空值会报空指针异常

2、原理

2.1 HashMap 在多线程下的问题

死循环问题:
假设存在 A 和 B 两个线程同时对 HashMap 扩容,两个线程执行速度有快慢,当 A 线程对 HashMap 完成扩容后,B 线程才刚刚将一个元素移动到新表,在 JDK1.7 版本中,由于采用头插法,那么最后 B 线程插入这个值的 next 会指向前面的值,造成死循环

2.2 ConcurrentHashMap 的线程安全

Get 方法:

  1. 为输入的 Key 做 Hash 运算,得到 hash 值。
  2. 通过 hash 值,定位到对应的 Segment 对象。
  3. 再次通过 hash 值,定位到 Segment 当中数组的具体位置。
    Put 方法:
  4. 为输入的 Key 做 Hash 运算,得到 hash 值。
  5. 通过 hash 值,定位到对应的 Segment 对象。
  6. 获取可重入锁。
  7. 再次通过 hash 值,定位到 Segment 当中数组的具体位置。
  8. 插入或覆盖 HashEntry 对象。
  9. 释放锁。
    从步骤可以看出,ConcurrentHashMap 在读写时需要二次定位,首先定位到 Segment,之后定位到 Segment 内的具体数组下标。
    Size 方法:
  10. 遍历所有的 Segment。
  11. 把 Segment 的元素数量累加起来。
  12. 把 Segment 的修改次数累加起来。
  13. 判断所有 Segment 的总修改次数是否大于上一次的总修改次数。如果大于,说明统计过程中有修改,重新统计,尝试次数+1;如果不是。说明没有修改,统计结束。
  14. 如果尝试次数超过阈值,则对每一个 Segment 加锁,再重新统计。
  15. 再次判断所有 Segment 的总修改次数是否大于上一次的总修改次数。由于已经加锁,次数一定和上次相等。
  16. 释放锁,统计结束。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值