java hashmap扩容大小_HashMap 扩容机制

java hashmap扩容大小_HashMap 扩容机制HashMap:publicHashMap(intinitialCapacity,floatloadFactor){//初始容量不能<0if(initialCapacity<0)thrownewIllegalArgumentException(“Illegalinitialcapacity:”+initialCapacity)…

大家好,又见面了,我是你们的朋友全栈君。

HashMap:

48304ba5e6f9fe08f3fa1abda7d326ab.png

public HashMap(int initialCapacity, floatloadFactor) {

//初始容量不能<0

if (initialCapacity < 0)throw new IllegalArgumentException(“Illegal initial capacity: ” +initialCapacity);

//初始容量不能 > 最大容量值,HashMap的最大容量值为2^30

if (initialCapacity >MAXIMUM_CAPACITY)

initialCapacity=MAXIMUM_CAPACITY;//负载因子不能 < 0

if (loadFactor <= 0 ||Float.isNaN(loadFactor))

throw new IllegalArgumentException(“Illegal load factor: ” +loadFactor);

//计算出大于 initialCapacity 的最小的 2 的 n 次方值。

int capacity = 1;

while (capacity

capacity<<= 1;this.loadFactor =loadFactor;

//设置HashMap的容量极限,当HashMap的容量达到该极限时就会进行扩容操作

threshold = (int) (capacity *loadFactor);//初始化table数组

table = newEntry[capacity]; init();

}

48304ba5e6f9fe08f3fa1abda7d326ab.png

在这里提到了两个参数:初始容量,加载因子。

这两个参数是影响HashMap性能的重要参数,其中容量表示哈希表中桶的数量,初始容量是创建哈希表时的容量,

加载因子是哈希表在其容量自动增加之前可以达到多满的一种尺度,它衡量的是一个散列表的空间的使用程度,负载因子越大表示散列表的装填程度越高,反之愈小。

对于使用链表法的散列表来说,查找一个元素的平均时间是O(1+a),因此如果负载因子越大,对空间的利用更充分,然而后果是查找效率的降低;

如果负载因子太小,那么散列表的数据将过于稀疏,对空间造成严重浪费。系统默认负载因子为0.75,一般情况下我们是无需修改的。

加载因子:

loadFactor

扩容:

48304ba5e6f9fe08f3fa1abda7d326ab.png

void addEntry(int hash, K key, V value, intbucketIndex) {

Entry e =table[bucketIndex];

table[bucketIndex]= new Entry(hash, key, value, e);

if (size++ >= threshold) //这里是关键,一旦大于等于threshold的数值

resize(2 * table.length); //将会引起容量2倍的扩大

}

48304ba5e6f9fe08f3fa1abda7d326ab.png

48304ba5e6f9fe08f3fa1abda7d326ab.png

void resize(intnewCapacity) {

Entry[] oldTable=table;

int oldCapacity =oldTable.length;

if (oldCapacity ==MAXIMUM_CAPACITY) {

threshold=Integer.MAX_VALUE;return;

}

Entry[] newTable= new Entry[newCapacity]; //新的容器空间

transfer(newTable); //复制数据过去

table =newTable;

threshold= (int)(newCapacity * loadFactor); //重新计算threshold的值

}

48304ba5e6f9fe08f3fa1abda7d326ab.png

48304ba5e6f9fe08f3fa1abda7d326ab.png

voidtransfer(Entry[] newTable) {//保留原数组的引用到src中,

Entry[] src =table;//新容量使新数组的长度

int newCapacity =newTable.length;

//遍历原数组

for (int j = 0; j < src.length; j++) {

//获取元素e

Entry e =src[j];if (e != null) {//将原数组中的元素置为null

src[j] = null;

//遍历原数组中j位置指向的链表

do{

Entry next =e.next;//根据新的容量计算e在新数组中的位置

int i =indexFor(e.hash, newCapacity);//将e插入到newTable[i]指向的链表的头部

e.next =newTable[i];

newTable[i]=e;

e=next;

}while (e != null);

}

}

}

48304ba5e6f9fe08f3fa1abda7d326ab.png

通过上面的transfer方法可以看出,

e.next=newTable[i];

newTable[i]=e;

链表存储倒过来了,最先出来的会将其next指向null,后面的就指向前一个,当然数据只有原来的一部分。

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

随着HashMap中元素的数量越来越多,发生碰撞的概率就越来越大,所产生的链表长度就会越来越长,这样势必会影响HashMap的速度,

为了保证HashMap的效率,系统必须要在某个临界点进行扩容处理。

该临界点在当HashMap中元素的数量等于table数组长度*加载因子。

但是扩容是一个非常耗时的过程,因为它需要重新计算这些数据在新table数组中的位置并进行复制处理。

所以如果我们已经预知HashMap中元素的个数,那么预设元素的个数能够有效的提高HashMap的性能。

问题:

当重新调整HashMap大小的时候,确实存在条件竞争,因为如果两个线程都发现HashMap需要重新调整大小了,它们会同时试着调整大小。

在调整大小的过程中,存储在链表中的元素的次序会反过来,因为移动到新的bucket位置的时候,HashMap并不会将元素放在链表的尾部,而是放在头部,这是为了避免尾部遍历(tail traversing)。

如果条件竞争发生了,那么就死循环了。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/149916.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 邮件服务器的架设方法「建议收藏」

    用Win2003架设邮件服务器很多企业局域网内都架设了邮件服务器,用于进行公文发送和工作交流。但使用专业的企业邮件系统软件需要大量的资金投入,这对于很多企业来说是无法承受的。其实我们可以通过WindowsServer2003提供的POP3服务和SMTP服务架设小型邮件服务器来满足我们的需要。一、安装POP3和SMTP服务组件WindowsServer2003…

    2022年4月8日
    187
  • 【开发工具】【smartctl】硬盘检测工具(smartctl)的使用

    【开发工具】【smartctl】硬盘检测工具(smartctl)的使用概述随着硬盘容量、速度的快速发展,硬盘的可靠性问题越来越重要,今天的单块硬盘存储容量可轻松达到1TB,硬盘损坏带来的影响非常巨大。不同的文件系统(xfs,reiserfs,ext3)都有自己的检测和修复工具。检测之前可以先使用dmesg命令查看有没有硬件I/O故障的日志,如果有,先用fsck看看是不是文件系统有问题,如果不是则可以使用下面介绍硬盘检测和优化方法来修复它。grep“error”/va/log/messages*;SMART是一种磁盘自我分析检测技术,早在90年代末就基本得到了

    2022年10月8日
    5
  • js保留小数点后面两位

    首先框的type一定要是numberbox才有precision这个属性格式化函数那里也需要调用precision2如果你需要保留四位formatter:precision4,options:{precision:4,},

    2022年4月7日
    45
  • CPU五级流水线_五级流水线是什么

    CPU五级流水线_五级流水线是什么取指:指令取指(InstrucTIonFetch)是指将指令从存储器中读取出来的过程。译码:指令译码(InstrucTIonDecode)是指将存储器中取出的指令进行翻译的过程。经过译码之后得到指令需要的操作数寄存器索引,可以使用此索引从通用寄存器组(RegisterFile,Regfile)中将操作数读出。执行:指令译码之后所需要进行的计算类型都已得知,并且已经从通用寄…

    2022年8月20日
    7
  • navicat 15激活码生成失败(注册激活)2022.02.03

    (navicat 15激活码生成失败)好多小伙伴总是说激活码老是失效,太麻烦,关注/收藏全栈君太难教程,2021永久激活的方法等着你。IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.net/100143.htmlCJM5ZJBPHS-eyJsaWNlbnNlSWQi…

    2022年3月31日
    428
  • redis主从复制原理是同步还是异步_kubernetes高可用架构

    redis主从复制原理是同步还是异步_kubernetes高可用架构史上最全的MySQL高可用架构之【主从复制】【故障转移】【读写分离】【负载均衡】

    2022年8月13日
    5

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号