• HashMap和ConcurrentHashMap和HashTable的底层原理与剖析


     

     

    HashMap  可以允许keynullvaluenull,但HashMap的是线程不安全的  HashMap 底层是数组 + 链表的数据结构

    • 在jdk 1.7 中 map集合中的每一项都是一个 entry  
    • 在jdk 1.8 中 map 集合中的每一项都是一个node

    这张图我解释一下 在每个HashMap中 维护了四个属性 分别是 hash ,map ,key ,next

    因为底层是数组加链表 数组的默认大小是16 每一个 用户put值的时候都会向这个数组进行添加 这里的添加算法就是 hash算法,一旦用户的数据向这个数组的某一项进行第二次辅助则这时就会使用链表的数据结构 一直向下延申 这个是jdk1.7 的做法 

    而到了jdk1.8以后 在延申的过程中一旦发现 延申的数量大于8个就会使用另一种的数据结构 红黑树以树的形式进行扩展进行添加

    这时肯定会有人问刚刚一直往下延申这时 的横向延申不够怎么办 就是数组的长度不足怎么办 这时数组当然也是会扩容 以原理的二倍进行扩容相对来说效率比较高

    HashMap 数组+链表+红黑树 在单线程的情况下简直是完美的 

    但在多线程的情况下是不完美的 会导致线程不安全

    线程不安全 :

    多线程操作一系列操作的时候和单线程操作表现的结果不致就说明线程非安全在 hashmap1.7中头插法hsah map是线程不安全的

    这时我们的Hashtable 出现了

    • hashtable不接受key 或者 value为空
    • 线程安全

    但是 是线程安全的 但在高并发 或者负载均衡的轮询等 效率太 低

    ConcurrentHashMap

    采用的是分段锁

    在并发的概念中 有一个编程思想是CAS方式 采用无锁的方式 保证线程的安全 保证了原子性 效率比 synchronized 高

    接下来我们对比一下HashMap 和 ConcurrentHashMap的put 方式

    Hashmap 的put方法

    ConcurrentHashMapput 方法

    点入到ConcurrentHashMap的put 方法

    这时我们在ConcurrentHashMap集合中看到 好多volatile关键字

    volatile

     这个关键字 保证每次读到的都是主内存里面最新的值

    • 扩容:段内扩容(段内元素超过该段对应Entry数组长度的75%触发扩容,不会对整个Map进行扩容),插入前检测需不需要扩容,有效避免无效扩容
    • ConcurrentHashMap默认将hash表分为16个桶,诸如get、put、remove等常用操作只锁住当前需要用到的桶。这样,原来只能一个线程进入,现在却能同时有16个写线程执行,并发性能的提升是显而易见的。
  • 相关阅读:
    执行存储过程 /创建存储过程:
    C# 设置本页面内所有TextBox为只读
    js 取得CheckBoxList的选中项的值
    把某些区域定为contentEditable="true"!
    如何在模态对话框中进行提交而不新开窗口?
    屏蔽 按键
    窗口与对话框之间的传值
    input button 的 onserverclick 事件
    checkbox js
    1.showModalDialog返回值给父窗口 2.winow.open开的窗口赋值给父窗口
  • 原文地址:https://www.cnblogs.com/wh1520577322/p/10020142.html
Copyright © 2020-2023  润新知