再三提醒,使用HashMap的时候小心点,offer收割机

本文详细介绍了HashMap、ConcurrentHashMap、LinkedHashMap和TreeMap之间的关系,重点讲述了HashMap的实现原理,包括哈希冲突的解决方法和线程不安全的原因。同时,强调了在不同场景下选择合适的线程安全Map类的重要性。
摘要由CSDN通过智能技术生成

我们都知道HashMap是线程不安全的,但是HashMap的使用频率在所有Map中确实属于比较高的。因为它可以满足我们大多数的场景了。

看一眼Map家族的关系图:

再三提醒,使用HashMap的时候小心点

Map是一个接口,我们常用的实现类有HashMap、LinkedHashMap、TreeMap,HashTable。

HashMap

=======

HashMap根据key的·值来保存value,需要注意的是,HashMap不保证遍历的顺序和插入的顺序是一致的。HashMap允许有一条记录的key为null,但是对值是否为null不做要求。

HashTable

=========

HashTable类是线程安全的,它使用synchronize来做线程安全,全局只有一把锁,在线程竞争比较激烈的情况下hashtable的效率是比较低下的。因为当一个线程访问hashtable的同步方法时,其他线程再次尝试访问的时候,会进入阻塞或者轮询状态,比如当线程1使用put进行元素添加的时候,线程2不但不能使用put来添加元素,而且不能使用get获取元素。所以,竞争会越来越激烈。相比之下,ConcurrentHashMap使用了分段锁技术来提高了并发度,不在同一段的数据互相不影响,多个线程对多个不同的段的操作是不会相互影响的。每个段使用一把锁。所以在需要线程安全的业务场景下,推荐使用ConcurrentHashMap,而HashTable不建议在新的代码中使用,如果需要线程安全,则使用ConcurrentHashMap,否则使用HashMap就足够了。

LinkedHashMap

=============

LinkedHashMap属于HashMap的子类,与HashMap的区别在于LinkedHashMap保存了记录插入的顺序。

TreeMap

=======

TreeMap实现了SortedMap接口,TreeMap有能力对插入的记录根据key排序,默认按照升序排序,也可以自定义比较强,在使用TreeMap的时候,key应当实现Comparable。

HashMap的实现

==========

Java7和Java7在实现HashMap上有所区别,当然Java7的效率要更好一些,主要是Java7的HashMap在Java7的基础上增加了红黑树这种数据结构,使得在桶里面查找数据的复杂度从O(n)降到O(logn),当然还有一些其他的优化,比如resize的优化等。 介于Java7的HashMap较为复杂,本文将基于Java7的HashMap实现来说明,主要的实现部分还是一致的,Java7的实现上主要是做了一些优化,内容还是没有变化的,依然是线程不安全的。 HashMap的实现使用了一个数组,每个数组项里面有一个链表的方式来实现,因为HashMap使用key的hashCode来寻找存储位置,不同的key可能具有相同的hashCode,这时候就出现哈希冲突了,也叫做哈希碰撞,为了解决哈希冲突,有开放地址方法,以及链地址方法。HashMap的实现上选取了链地址方法,也就是将哈希值一样的entry保存在同一个数组项里面,可以把一个数组项当做一个桶,桶里面装的entry的key的hashCode是一样的。

再三提醒,使用HashMap的时候小心点

上面的图片展示了我们的描述,其中有一个非常重要的数据结构Node<K,V>,这就是实际保存我们的key-value对的数据结构,下面是这个数据结构的主要内容:

final int hash;

final K key;

V value;

Node<K,V> next;

一个Node就是一个链表节点,也就是我们插入的一条记录,明白了HashMap使用链地址方法来解决哈希冲突之后,我们就不难理解上面的数据结构,hash字段用来定位桶的索引位置,key和value就是我们的数据内容,需要注意的是,我们的key是final的,也就是不允许更改,这也好理解,因为HashMap使用key的hashCode来寻找桶的索引位置,一旦key被改变了,那么key的hashCode很可能就会改变了,所以随意改变key会使得我们丢失记录(无法找到记录)。next字段指向链表的下一个节点。

HashMap的初始桶的数量为16,loadFact为0.75,当桶里面的数据记录超过阈值的时候,HashMap将会进行扩容则操作,每次都会变为原来大小的2倍,直到设定的最大值之后就无法再resize了。

下面对HashMap的实现做简单的介绍,具体实现还得看代码,对于Java7中的HashMap实现,还需要能理解红黑树这种数据结构。

1、根据key的hashCode来决定应该将该记录放在哪个桶里面,无论是插入、查找还是删除,这都是第一步,计算桶的位置。因为HashMap的length总是2的n次幂,所以可以使用下面的方法来做模运算:

h & (length-1)

h是key的hashCode值,计算好hashCode之后,使用上面的方法来对桶的数量取模,将这个数据记录落到某一个桶里面。当然取模是Java7中的做法,Java7进行了优化,做得更加巧妙,因为我们的length总是2的n次幂,所以在一次resize之后,当前位置的记录要么保持当前位置不变,要么就向前移动length就可以了。所以Java7中的HashMap的resize不需要重新计算hashCode。我们可以通过观察java7中的计算方法来抽象出算法,然后进行优化,具体的细节看代码就可以了。

2、HashMap的put方法

再三提醒,使用HashMap的时候小心点

上图展示了Java7中put方法的处理逻辑,比Java7多了红黑树部分,以及在一些细节上的优化,put逻辑和Java7中是一致的。

3、resize机制

HashMap的扩容机制就是重新申请一个容量是当前的2倍的桶数组,然后将原先的记录逐个重新映射到新的桶里面,然后将原先的桶逐个置为null使得引用失效。后面会讲到,HashMap之所以线程不安全,就是resize这里出的问题。

为什么HashMap线程不安全?
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)

最后

javascript是前端必要掌握的真正算得上是编程语言的语言,学会灵活运用javascript,将对以后学习工作有非常大的帮助。掌握它最重要的首先是学习好基础知识,而后通过不断的实战来提升我们的编程技巧和逻辑思维。这一块学习是持续的,直到我们真正掌握它并且能够灵活运用它。如果最开始学习一两遍之后,发现暂时没有提升的空间,我们可以暂时放一放。继续下面的学习,javascript贯穿我们前端工作中,在之后的学习实现里也会遇到和锻炼到。真正学习起来并不难理解,关键是灵活运用。

资料领取方式:点击这里免费领取前端全套学习资料

css源码pdf

JavaScript知识点
,关键是灵活运用。

资料领取方式:点击这里免费领取前端全套学习资料

[外链图片转存中…(img-QOekxhR1-1712301378348)]

[外链图片转存中…(img-7ovxgboi-1712301378348)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值