HashTable, HashMap, ConcurrentHashMap 之间的区别

HashTable、HashMap、ConcurrentHashMap 都是存储键值对的容器,其区别如下:

  1. HashTable是线程安全的,HashMap 不是线程安全的。在并发环境下,HashTable 性能表现比 HashMap 差。 HashTable 不允许 key 或 value 为 NULL,而 HashMap 允许 key 或 value 为 NULL。 HashTable 进行 resize 时,会锁住整个 HashTable 表,导致所有操作被阻塞;而 HashMap 初始大小固定,resize 导致效率低下,但是 JDK1.8 之后 HashMap 进行 resize 时,并不会锁整个 HashMap,而是只锁住相关 Node 链表,这一点在多线程环境中大大提高了效率。

  2. HashMap 与 ConcurrentHashMap HashMap 是非线程安全的,ConcurrentHashMap 是线程安全且并发性高的。

ConcurrentHashMap 采用分段锁技术,将哈希表分为多个 Segment(段),每个 Segment 采用独立锁实现并发控制,不同线程访问不同 Segment 时,不会发生锁竞争,从而提高了并发访问效率。而 HashMap 在并发访问时需要采用锁机制进行同步,锁竞争导致效率降低。

总结:如果需要在多线程环境下使用容器,建议使用 ConcurrentHashMap;如果对容器线程安全没有要求,且在单线程环境下访问比较频繁,推荐使用 HashMap。而因为 HashTable 性能比较低,建议尽量避免使用 HashTable。

对于线程安全的hashTable来说, 只是简单的把put和get方法加上了synchronized关键字, 也就是说在一个线程进行put或者get的时候, 其他线程需要阻塞等待, size属性也是被synchronized修饰的, 访问起来比较慢, 一旦触发扩容, 对于hashTable来说就意味着大量的内存拷贝, 此时当元素多了之后 ,拷贝效率就会非常的低下.

对于ConcurrentHasMap, 相比于 Hashtable 做出了一系列的改进和优化. Java1.8 为例 读操作没有加锁(但是使用了 volatile 保证从内存读取结果), 只对写操作进行加锁. 加锁的方式仍然 是是用 synchronized, 但是不是锁整个对象, 而是 "锁桶" (用每个链表的头结点作为锁对象), 大大降 低了锁冲突的概率. 充分利用 CAS 特性. 比如 size 属性通过 CAS 来更新. 避免出现重量级锁的情况. 优化了扩容方式: 化整为零 发现需要扩容的线程, 只需要创建一个新的数组, 同时只搬几个元素过去.

扩容期间 , 新老数组同时存在 .
后续每个来操作 ConcurrentHashMap 的线程 , 都会参与搬家的过程 . 每个操作负责搬运一小
部分元素 .
搬完最后一个元素再把老数组删掉 .
这个期间 , 插入只往新数组加 .
这个期间 , 查找需要同时查新数组和老数组

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值