zoukankan      html  css  js  c++  java
  • HashMap和ConcurrentHashMap详解

    引言

      本文主要讲解,Java中hashMapConcurrentHashMap的原理内容。

    HashMap

      在java JDK 1.7之前 hashMap采用的是 数组+链表 的形式;而在 JDK 1.8 之后 hashMap 采用的是 数组+链表[单向/双向]+红黑树 的形式。

    内存模型

      hashMap内存模型内容,如下图所示:

     描述map.put(1, "Jamin");

    1. 得先创建一个数组:Node[] table = new Node(size);
    2. 根据key、value值,创建一个Node:new Node();
    3. 需要判断当前Node对象放在数组中的那个位置
      • 随机算法: new Random.nextInt(size)----->链表太长,容易导致put和查询的效率变慢
      • hash算法:Node节点下标的位置
        • 可以拿到key的hash值 key.hashCode()
        • 尽量减少hash算法的重复下标的可能性------>采用 %运算 hashCode()%(size-1)  或者 &运算 hashCode()&(size-1)  以及 hashCode高低16位 异或运算   hashCode()^(size-1) 
    static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16)
    }
      • 为保证hash算法的下标尽可能的不重复, 则数组的大小必定是2^n;  如果设定的数组大小非2^n, 则JDK会数组大小进行调整
      • 根据index, 将Node对象存储在对应数组的位置
        • 数组下标index的位置没有Node: 直接存放
        • 数组下标index的位置有Node
          • key值相同: 直接替换value值
          • key值不相同: 以单向链表的形式进行存储(而当链表对象达到一定长度的时候, JDK则会对该链表进行转为 红黑树)
      • 数组扩容----> 根据当前数据结构中Node节点的数量, 如果超过一定的数值标准(0.75倍)的时候, JDK 则会对数组进行扩容
      • 数组Node迁移
        • 遍历老数组的索引位置,找出索引位置不为空的Node
        • 对于不为空的Node索引位置, 进行判断
          • 没有Node---> next == null
          • 有Node--> 链表的方式 hash&(newCap - 1)--->关注每个Node节点的hash倒数第(n+1)位是否为0 e,hash & n--->0. 新数组原来的位置 1.新数组原来的位置+2^n

    ConcurrentHashMap

      hashMap线程安全的设计原理

    put整个过程中是否是线程安全?

      在JDK 1.8中 使用 ConcurrentHashMap 

    • 初始化数组大小 (保证线程安全)--> CAS 无锁化的机制保障线程的安全性(乐观锁机制)  [说明:变量值与内存中最新值比较是否相等,判断其修改权限]
    • put-操作 (保证线程安全)
      • synchronized --> 导致整个数组的数据都会被锁, 效率极其低下
      • 数组下标位置为空的时候,  CAS乐观锁机制
      • 数组下标不为空的时候,  数组下标位置定制自定义锁(synchronized)

    数组扩容会有线程安全的问题, 怎么解决?

      当一个数组需要扩容的时候, 当线程T1 正在创建数组/数据迁移的时候; T2/3/4/5 线程 想来put数据, 那么数据允许put么?

      no -->  不允许插入数据, 但会利用其它线程(T2/3/4/5)来帮助线程 T1 迁移

        帮助迁移流程:

      1. 第一个线程负责创建新的数组
      2. 所有的线程领取各自的任务, 并且以(size)大小为单位的领取(从后往前)
  • 相关阅读:
    新概念英语第三册21-40课(转)
    多线程---线程通信
    多线程----线程同步
    多线程----线程创建的四种方式
    从0开始整合SSM框架-1.mybatis
    easyUI datagrid 动态绑定列名称
    java分享第五天(数组)
    java分享第四天(循环)
    java分享第三天(异常)
    java分享第二天(变量及命名规范)
  • 原文地址:https://www.cnblogs.com/huanghzm/p/11811592.html
Copyright © 2011-2022 走看看