• HashMap、HashTable、CurrentHashMap对比


    • 😜           是江迪呀
    • ✒️本文关键词Java集合MapCurrentHashMap
    • ☀️每日   一言坚持自己的风格,面对未知的一切!

    在这里插入图片描述

    一、HashMapHashTableCurrentHashMap对比

    1.1 CurrentHashMapHashMap对比

    由于HashMap在多线程下不安全诞生了HashTable由于HashTable效率太低诞生了CurrentHashMapCurrentHashMap它大量的使用了volatilefinalCASlock-free技术来减少锁竞争对于性能的影响。ConcurrentHashMap避免了对全局加锁改成了局部加锁操作。这样就极大的提高了 并发环境下的操作速度。

    所以CurrentHashMap线程是安全的,HashMap线程不安全,在多线程下,使用HashMap进行put操作或造成死循环,导致CPU的利用率接近100%,使用并发情况下不能使用HashMap

    1.2 HashMapHashTable对比

    HashMapHashTable的实现原理几乎一致,差别是:HashTable不允许keyvaluenull。HashTable是线程安全的。但是Hastable实现线程安全的代价很大,get/put的所有相关操作都是synchronized的,这相当于给hash表加上了一把大锁,多发生多线程操作HashTable时,只要有一个线程操作HashTable其它线程必须阻塞,相当于将所有多线程操作串行化,性能和效率很差。

    二、JDK1.7ConcurrentHashMap实现原理

    在JDK1.7中ConcurrentHashMap使用的是数组+Segment+分段锁对的方式实现。Segment(分段锁)–减少锁的粒度,ConcurrentHashMap中的分段锁被称为Segment,它类似与 HashMap对的结构,及内部拥有一个Entry数组,数组中的每个元素又是一个链表。同时又是一个ReentrantLock(Segment继承了ReentrantLock

    2.1 ConcurrentHashMap的内部结构

    ConcurrentHashMap采用分段锁技术,将数据分为一段一段存储, 然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其它段的数据也能被其它线程访问。能够实现真正意义的并发访问,ConcurrentHashMap结构图:
    在这里插入图片描述

    从上面的结构我们可以看出,ConcurrentHashMap定位一个元素的过程需要进行两次操作。第一次定位到底Segment,第二次定位定位到元素所在的链表的头部。
    好处:写操作的时候可以只对元素所在的Segment进行加锁即可,不会影响到 其它的Segment,这样在理想状态下,ConcurrentHashMap可以最高同时支持和Segment数量一样多的写操作(刚好这些写操作都非常平均的分配到,所有的Segment上)并发能力可以大大的提高。
    坏处:这种结构带来的副作用就是,存值时的过程要比HashMap要长。Segment的数量是根据并发总量来决定的,比如来说,并发总量是8,那么segment的数量就是8

    2.2 为啥JDK1.8版本的ConcurrentHashMap的并发能力可以大大的提高?

    JDK8中ConcurrentHashMap采用了数组+链表+红黑树的实现方式来设计,内部采用大量的CAS操作。

    CAScompare and swap的缩写,就是比较并交换。CAS是一种基于锁的操作,是乐观锁
    锁分为乐观锁悲观锁,悲观锁就是将资源锁住后,等当前获得锁的对象将锁释放后,下一个线程才能访问。而乐观锁采用了宽泛的态度,通过某种方式不加锁来处理资源,比如通过给记录加version来获取数据,性能较悲观锁有很大的提高。
    CAS操作包含三个操作数:
    (1)内存位置(V);
    (2)预期值(A);
    (3)新值(B);
    如果内存地址里面的值和A的值是一样的,那么就将内存中的值更新成BCAS是通过无限循环来获取数据的,如果第一轮循环中,a线程获取地址里面的值被b线程修改了,那么a线程需要自旋,到下次循环才有可能被执行。

    JDK8中彻底放弃了Segment转而采用的是Node。其设计思想不再是1.7中的分段锁机制。
    Node:保存key,value以及key的Hash值的数据结构,其中value和next都是用volatile修饰,保证并发内存的可见性。java8中的ConcurrentHashMap的结构基本和Java8中的HashMap一致,不过保证线程安全。在JDK8中的ConcurrentHashMap引入了红黑树,红黑树是一种性能非常好的二叉查找树,其查找性能是O。当ConcurrentHashMap中的链表的长度大于某个阈值(这个阈值是8)的时候将链表转化为红黑树,以提高查询效率。

    三、总结

    3.1 JDK1.8的ConcurrentHashMap结构和Hashmap的结构比较

    JDK1.8的ConcurrentHashMap结构和Hashmap的结构很接近,只是增加了同步操作来控制并发:

    • JDK1.7采用: 数组+Segment+HashEntry
    • JDK1.8采用: Synchronized+CAS+HashEntry+红黑树

    3.2 JDK1.7和JDK1.8中的ConcurrentHashMap的比较:

    • 数据结构:放弃了Segment分段锁机制,采用了数组+链表+红黑树
    • 保证线程安全机制: 1.7采用Segment分段锁机制,其中Segment继承ReentrantLock。1.8采用CAS+Synchronized保证线程安全。
    • 锁的粒度: 1.7采用的对响应进行数据操作的Segment加锁,1.8调整为对每个数组元素进行加锁(node)减小了锁的粒度,提高的性能。
    • 链表转化为红黑树。
    • 查询时间复杂度: 从原来的遍历链表O(n),变成遍历红黑树O(LogN)
  • 相关阅读:
    VS2019 Qt源码编译
    怎么快速入门一种编程语言
    使用tkinter开发GUI程序4 -- tkinter常见控件的特征属性(第二部分)
    【企业架构】现代企业架构方法——第 1 章
    分布式缓存架构
    Apache Commons CSV 基本使用
    Toronto Research Chemicals萜烯分析丨反式植物醇
    ASP.NET Core 8 的 Web App
    SpringBoot事件监听器源码分析
    大数据时代下统计数据质量的控制方法
  • 原文地址:https://blog.csdn.net/qq_42785250/article/details/132796081