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

【JDK】HashMap

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

【JDK】HashMap

???哪些实现方式?::直接定址法、数字分析法、除留余数法、分段叠加法、平方取中法、伪随机数法

**->:**HashMap在get(Object key)时,

(1)先高低位异或重新计算获得hashcode值,然后与运算取模计算得到在数组中的存储下标index

(2)如果是bucket里的第一个节点,则直接命中;否则有冲突,通过key.equals(k)查找对应的Node,若为树则O(logn),若为链表则 O(n);

**->:**碰撞探测,也即上述set和get方法中提到的hashCode相同时,则数组index位置处的bucket中以链表形式进行存储和查找

描述:HashMap初始化时,系统会创建一个长度为capcity(16)的的Node数组,该Node数组中可以存储node元素的位置被称为桶bucket(每个桶均有其索引,且只存储一个node元素,且node对象含有一个引用变量,用以指向下一个node进而构成node链表结构)

**->:**非线程安全,这是由于:

(1)不同线程在put操作时,如果是其中一个线程改变了某一键值对的value,那么其他的线程就get不到预期的值,而且值是在不停改变的,因此这样也不是线程安全的;

(2)在多线程中,当有两个线程同时在put操作的时候,如果存在扩容调用resize,那么也就是resize被两个线程同时调用,可能会产生环形链表,然后再执行get操作就会触发死循环引起CPU的100%问题

(3)fail-fast,如果在使用迭代器的过程中有其他线程修改了map的结构,则将抛出ConcurrentModificationException异常,也即所谓的fail-fast策略,此时开发人员应该注意线程安全问题

(说明)(a)避免多线程写时使用HashMap,单写多读是没有问题的;(b)或者为什么要在多线程中使用HashMap,Sun官方都不认为HashMap在多线程中的这个问题是个bug,因为HashMap本来就是不支持多线程使用的,如果需要并发的话就用ConcurrentHashMap;©或者通过方法Collections.synchroziedMap(Map),将HashMap转化为线程同步的Map

注意事项:

(1)使用String、Integer等引用类型的封箱wrapper类作为键Key使用;String最为常用,不可变且final的,已经重写的equals和hashCode方法 -> 当对象插入到HashMap之后,且Key就不会再改变了

(2)equals相等,必然hashCode相等 <=> hashCode不相等,必然equals不相等;

(3)hashCode相等,equals可能不相等;

(4)Hashtable使用了线程同步锁保护,也即Hashtable是粗暴地添加了同步锁(synchronized),导致性能会有损失 -> 更好的方式是使用ConcurrentHashMap,该类采用的是一种分段锁的机制实现线程安全的,后续将在单独一个篇幅中进行介绍!

【问4】??HashMap怎样解决冲突,讲一下扩容过程,假如一个值在原数组中,现在移动了数组,位置肯定改变了,那是什么定位到在这个新数组中的位置?

答:将新节点加到链表后,容量扩充为原来的两倍,然后对每个节点重新计算hash值,这个值只会出现在两个地方,一个是原下标的位置,另一种是在下标为<原下标+原容量>的位置

【问5】??抛开HashMap,hash冲突有哪些解决办法?

答:开放定址法,链地址法,再哈希法、建立公共溢出区

【问6】??针对HashMap中某个Node链太长,查找的时间复杂度可能达到O(n),怎么优化?

答:将链表转为红黑树,JDK1.8已经实现,时间复杂度变为O(logn)

三、Hashtable、HashMap、ConcurrentHashMap

ConcurrentHashMap使用分段锁技术,允许多个修改操作并发进行。ConcurrentHashMap内部使用段来表示这些不同的部分,每个段其实就是一个小的Hashtable,它们有自己的锁。只要多个修改操作发生在不同的段上,它们就可以并发进行。

Hashtable是一个线程安全的类,它使用synchronized来锁住整张Hash表来实现线程安全,即每次锁住整张表让线程独占

有些方法需要跨段,比如size()和containsValue(),它们可能需要锁定整个表而而不仅仅是某个段,这需要按顺序锁定所有段,操作完毕后,又按顺序释放所有段的锁。这里“按顺序”是很重要的,否则极有可能出现死锁,在ConcurrentHashMap内部,段数组是final的,并且其成员变量实际上也是final的,但是,仅仅是将数组声明为final的并不保证数组成员也是final的,这需要实现上的保证。这可以确保不会出现死锁,因为获得锁的顺序是固定的。

HashMap类:

  • Node:链表节点,包含了key、value、hash、next指针四个元素

  • table: 《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》无偿开源 威信搜索公众号【编程进阶路】 Node类型的数组,里面的元素是链表,用于存放HashMap元素的实体

  • size:记录了放入HashMap的元素个数

  • loadFactor:负载因子

  • threshold:阈值,决定了HashMap何时扩容,以及扩容后的大小,一般等于table大小乘以loadFactor

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

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

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