HashMap核心总结

数据结构:

数组+链表+红黑树

  1. 为啥用数组:数组使用连续存储单元存储数据,查找复杂度为O(1),非常快,但是移动效率低,为O(n)
  2. 通过hash算法得到数组下标,index=hashcode%数组长度,但是hash算法有可能会对不同的key算出同样的hash值,导致hash冲突
  3. 为了解决hash冲突,引入线性链表:单向链表:插入删除效率很高,O(1),查找效率低O(n)
  4. 当链表中元素越来越多,链表会越来越长,为了优化查询效率,引入红黑树
  5. 红黑树确保没有一条路径会比其他路径长出两倍,从而是接近平衡的,对于插入、查找,时间复杂度最坏为O(log(n))

容量:

  1. 默认初始容量16
  2. 在调用put时初始化,一般的取模运算index=hashcode%数组长度效率太低,用的是位运算,位运算要求数组长度必须是2的指数次幂
  3. 扩容会扩到原来的两倍,扩容会需要rehash,会增加处理时间
  4. jdk7当高并发场景下多线程同时对一个hashmap扩容,会导致死锁
  5. 死锁原因:移动链表内容时采用头插法,节点顺序倒置,一旦两个线程同时操作,有可能进行两次倒置,彼此next互指,造成死锁
  6. jdk8扩容不再需要rehash,不再采用倒置的头插法,避免了死锁,再加上红黑树的优势,效率比7提高15%,
  7. 当链表中节点超过8个就会转红黑树,当原表中元素超过75%时即触发扩容,扩容因子=0.75

 为什么扩容因子是0.75:提高空间利用率和 减少查询成本的折中,主要是泊松分布,0.75的话碰撞最小

 为什么阈值是8:在理想情况下,使用随机哈希码,节点出现的频率在hash桶中遵循泊松分布,按照泊松分布的计算公式计算出了桶中元素个数和概率的对照表,可以看到链表中元素个数为8时的概率已经非常小,再多的就更少了,所以原作者在选择链表元素个数时选择了8,是根据概率统计而选择的

HashDos攻击问题:

  • 原因

无论我们服务端使用什么语言,我们拿到json格式的数据之后都需要做jsonDecode(),将json串转换为json对象,而对象默认会存储于Hash Table,而Hash Table很容易被碰撞攻击。我只要将攻击数据放在json中,服务端程序在做jsonDecode()时必定中招,中招后CPU会立刻飙升至100%。16核的CPU,16个请求就能达到DoS的目的。

  • 解决

首先我们需要增加权限验证,最大可能的在jsonDecode()之前把非法用户拒绝。其次在jsonDecode()之前做数据大小与参数白名单验证。旧项目的改造与维护成本如果很高,建议自己重写jsonDecode()方法。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值