栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

HashMap

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

HashMap

HashMap的特点

存储数据(key,value)键值对的形式、key可以为null,同样的key会被覆盖掉

数据结构

底层采用数组、链表、红黑树实现(1.8)

存储方式的特点

通过哈希算法,将任意长度的key通过哈希算法(散列算法)变换成一个长度固定的key(地址)

哈希算法

会先将key提取出来,然后把key中的每一个字符转换成ascii码,进行取模,就可以算出哈希表的数组下标。通过取莫得方式是为了节省空间,想想如果有一个名字转换成ascii码后是上万的数字,那么为了存储这一个ascii码就要开辟一个上万容量的数字,造成的浪费可谓是相当大,通过取莫把值控制在一定的范围内。

 但是如果仅仅以数组作为数据结构,那么就会出现一个新的问题,如果是这时候又存入一个值foes,它取取模之后也是9,那么就会出现冲突,按照数组的定义,这时候就会把lies替换为foes,这就是hash冲突

为了解决hash冲突,又引入了链表,当出现冲突的时候,就挂在链表上。

 新数据的插入在jdk7采用的是头插法(插在链表头部),在jdk8采用的是尾插法(插在链表尾部)

在jdk8中,又引入了红黑树得概念,因为链表得遍历是通过头节点进行遍历的,当链表过长的时候,假设有70w条数据,要查最后一个数据,就需要遍历70w次,而红黑树可以通过二分查找大量的减少遍历次数。当链表长度大于等于8的时候就会转变成红黑树,当红黑树节点小于等于6的时候就会变成链表

jdk7采用的头插法会产生的问题(cpu100)

先分析单线程情况下的插入运行流程

现在要存储A、B两个元素

 此时达到了扩容的阈值,准备进行扩容。扩容的时候会遍历链表中的元素,转移到新数组,使用的是头插法,而先插入B,再插入A,那么遍历链表的时候就会先读取到A,然后插入数组,再读取到B。所以扩容重排之后就会由A->B变为B->A。在单线程模式下是安全的

 分析一下多线程模式下的扩容过程

两个线程同时插入同一个位置。

当插入AB完毕之后,先由线程1对数组进行扩容,而此时扩容已经完成,但是数据还没有完成迁移,在即将要对数据进行重排得时候,时间片用完了

 接下来由线程2获得一个扩容后的线程,这时候要对数据进行迁移,所以此时线程而得数组是这样 ,也就是由B指向A。

此时得情况就是,线程1中使A指向B,2线程中使B指向A。两个地址互相指向,造成了一个死循环。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/666534.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号