HashMap, Hashtable, ConcurrentHashMap 之间的区别

Key 值是否可以为空

HashMap

这是 HashMap 的 hash 方法, 可以看出如果 key 值为空, hash方法的返回值即为0
在这里插入图片描述

Hashtable

而Hashtable源码中的put 方法中的 key 如果为空, hashCode方法会抛出空指针异常

在这里插入图片描述例如:

在这里插入图片描述

ConcurrentHashMap

ConcurrentHashMap 的Key也不可以为空, 如下源码中的 put 方法, 如果 Key == null, 则会抛出空指针异常
在这里插入图片描述

Hashtable 的加锁问题

都知道Hashtable和ConcurrentHashMap 是线程安全的, 但是为什么 Hashtable 的效率低?

如下, 这是 Hashtable 源码中的一部分方法, Hashtable 的很多方法都是非常直接暴力地用 synchronized 修饰, 锁的范围太大, 很多不必要且频繁的加锁释放锁的操作大大降低了 Hashtable 性能

在这里插入图片描述

相比 Hashtable 和 ConcurrentHashMap

对于加锁, ConcurrentHashMap 做的比 Hashtable 更好

Hashtable 的加锁是针对整个哈希表进行加锁, 毋庸置疑, Hashtable 锁细度太粗, 一个锁就覆盖了所有哈希桶, 按理来说, 往不同的桶里放元素, 也不会让彼此收到影响

在 java 8 之前, 一个锁管理多个哈希桶, 即多个哈希桶分配一个锁。在 java 8 开始, ConcurrentHashMap 中哈希表中的每个哈希桶都有一个锁, 这每个哈希桶的锁对象就是当前链表的头结点, 锁细度更细, 能有更多线程操作一份表。

除此之外

ConcurrentHashMap 还有一些优化和特点

ConcurrentHashMap 充分使用了 CAS 的特性, 通过 CAS 维护一下变量等, 比如当前元素个数size

且针对 ConcurrentHashMap 的扩容也做出了细致的优化, 不同于 HashMap, HashMap 扩容是等某一次 put 后发现负载因子不达标后开始扩容, 新建一个表, 重新将元素哈希进新表, 这会导致这一次 put 的时间非常长。

而 ConcurrentHashMap 则是将扩容的操作和成本平摊, 如果发现了有操作 ConcurrentHashMap 的线程需要扩容, 就会创建一个新表, 然后顺便将原表中的几个元素重新哈希到新表, 在扩容没有完成前, 新表和老表都会共存, 然后接下来操作 ConcurrentHashMap 的线程中, 每次操作都会顺手将原表中若干个元素哈希到新表(搬运)。 在这期间, 每次插入操作都会放在新表中, 查询操作即同时在新表和旧表中查询。直到扩容完成, 旧表删除。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

答辣喇叭

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

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

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

打赏作者

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

抵扣说明:

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

余额充值