0
点赞
收藏
分享

微信扫一扫

如何设计一个订单超过5分钟不支付就自动去掉订的设计?都有哪些方案?

水沐由之 03-21 16:00 阅读 3

hashmap专题

常见map

  • hashtable线程安全,但效率太低。
  • hashmap 线程不安全。
  • LinkedHashMap线程也不安全
  • ConcurrentHashMap线程安全

hashMap

hashmap的数据结构有数组和链表来实现对数据的存储,但这2个基本上是两个极端。

  • 数组:数组的存储区是连续的,占用内存比较严重,故空间复杂度很大,但因其地址连续,查找很快。数组的特点就是,寻址容易,插入和删除困难。
  • 链表 链表的存储区离散,占用内存比较宽容,故空间复杂度小,但时间复杂度大(因其内存地址不连续,查找会慢),链表的特点:寻址慢,插入和删除容易

JDK7及以前版本,hashmap是数组+链表结构,
JDK8以后,Hashmap是数组+链表+红黑树

jdk1.8HashMap新变化

  • HashMap map = new HashMap();//默认情况下,先不创建长度为16的数组。
  • 当首次调用map.put()时,在创建长度为16的数组 。
  • 数组为Node类型,在jdk17中称为Entry数组。
  • 当数组指定索引位置的链表长度>8时,且map中的数组长度>64时,此索引位置上的所有key-value对使用红黑树进行存储。

hashmap源码中重要的常量

  • DEFAULT_INITIAL_CAPACITY : 默认16,HashMap的默认容量
  • MAXIMUM_CAPACITY :默认2^30, HashMap的最大支持容量
  • DEFAULT_LOAD_FACTOR:默认0.75, HashMap的默认加载因子
  • TREEIFY_THRESHOLD:默认8 Bucket中链表长度大于该默认值,转化为红黑树
  • UNTREEIFY_THRESHOLD: 默认6,Bucket中红黑树存储的Node小于该默认值,转化为链表
  • MIN_TREEIFY_CAPACITY: 默认64,桶中的Node被树化时最小的hash表容量。(当桶中Node的数量大到需要变红黑树时,若hash表容量小于MIN_TREEIFY_CAPACITY时,此时应执行resize扩容操作这个MIN_TREEIFY_CAPACITY的值至少是TREEIFY_THRESHOLD的4倍。)
  • table: 存储元素的数组,总是2的n次幂

存储结构

jdk1.8 put方法

在这里插入图片描述

在jdk1.8后,内部数据结构使用数组+链表+红黑树进行存储。

  • 数组类型为Node[],每个Node都保存了某个KV键值对元素的key、value、hash、next等值。
  • 链表 他由一系列节点组成,每个节点包含两部分:数据和指向下一个节点的指针。
  • 当链表的长度超过8并且数组长度大于64,为了避免查找搜索性能下降,该链表会转换成一个红黑树。

put 存入数据过程

  1. hashmap在存储数据时,会将key和value封装在一个Node[]
  2. 调用key的hashcode()方法获取key的哈希码。
  3. 通过转换算法将其转换为数组的下标。
  4. 当数组下标没有值,就直接将此Node[]放在这个下标
  5. 当数组下标下有值,就会将key和链表上的每一个值进行比较
  6. 如果equal()都返回false则将其加入链表最后
  7. 如果equal()和链表某个节点返回true则将其节点进行覆盖

取数据过程get()

  1. 根据key的值算出hashcode
  2. 通过转换算法将其转换为数组的下标
  3. 如果当前下标为null则直接返回空
  4. 如果当前下标是链表,会使用equal()方法和链表上的节点进行比较
  5. 如果都返回false则返回空
  6. 如果有一个节点为true则返回当前节点的值

扩容

  • loadFactor 负载因子,默认值0.75

当Hashmap中的元素个数超过数组大小(数组总大小length,不是数组中个数size)loadFactor 时,就 会 进 行 数 组 扩 容 , loadFactor 的 默 认 值(DEFAULT_LOAD_FACTOR)为0.75, 这是一个折中的取值。 也就是说, 默认情况下, 数组大小(DEFAULT_INITIAL_CAPACITY)为16, 那么当HashMap中元素个数超过160.75=12(这个值就是代码中的threshold值, 也叫做临界值)的时候, 就把数组的大小扩展为 2*16=32, 即扩大一倍, 然后重新计算每个元素在数组中的位置, 而这是一个非常消耗性能的操作, 所以如果我们已经预知HashMap中元素的个数, 那么预设元素的个数能够有效的提高HashMap的性能。

hashmap 树化/链化

当hashmap中的其中一个链表的对象个数达到了8个,此时如果capacity没有达到64个,那么hashmap会先扩容解决,如果已经达到了64,那么这个链会变成树,节点类型由Node变成treeNode类型。当然,如果当映射关系被移除后,下次resize方法时判断树的节点小于6个,也会把树在转换为链表。

hashmap的容量 桶的数量为什么要是2的n次方?

HashMap为了存取高效,要尽量较少碰撞,就是要尽量把数据分配均匀,每个链表长度大致相同。
关键就在于把当前数据存放到哪一个桶中,这个算法就是取模运算。

为什么可以减少碰撞?
举个例子,现在两个hash分别是2和3:
比如 length 为 9 的情况:3&(9-1)=0 2&(9-1)=0 ,都在0上,碰撞了;
比如 length 为 8 的情况:3&(8-1)=3 2&(8-1)=2 ,不同位置上,不碰撞;

hashmap为什么线程不安全

  1. 并发修改导致数据不一致(hash碰撞)。
  2. 并发扩容导致死循环或者数据丢失。
举报

相关推荐

0 条评论