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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • c语言图书管理系统源代码_c语言图书信息管理系统

    c语言图书管理系统源代码_c语言图书信息管理系统一、目的通过设计一个图书管理系统的程序,全面运用课程的主要知识点,巩固对模块化程序设计、文件操作的理解,提高软件编程能力。二、涉及的知识点循环、分支语句、函数、数组、函数、结构体、指针、链表、文件读取操作等等三、程序已经实现的功能点(用100-200字进行说明)(1)程序具有以下功能,操作流程见下图:登录界面:输入用户名(admin)、密码(20190611),只有用户名、密码同时正确(信息存放在文件中)才能进入系统主菜单,否则需要重新输入用户名、密码。(同时输入3次错误将退出程序)。操

    2022年10月11日
    0
  • python 字符转义(url中文转义)

    URL特殊字符需转义1、空格换成加号(+)2、正斜杠(/)分隔目录和子目录3、问号(?)分隔URL和查询4、百分号(%)制定特殊字符5、#号指定书签6、&号分隔参数转义字符的原因:如果你的表单使用get方法提交,并且提交的参数中有“&”等特殊符的话,如果不做处理,在service端就会将&后面的作为另外一个参数…

    2022年4月14日
    76
  • WaitForSingleObject_调用wait方法时,线程会放弃对象锁

    WaitForSingleObject_调用wait方法时,线程会放弃对象锁摘要在MicrosoftWindows平台上有几种以原子方式锁定代码和数据的不同方法。此白皮书的主要目的是向开发人员简要介绍Windows中进行锁定的不同方法以及与这些锁定有关的相应性能开销。因为未来架构将是多核架构,因此此信息非常适用。简介多线程软件应用对于提升英特尔内核架构的性能至关重要。锁定代码通常是多线程应用中运行最频繁的代码。确定要使用的锁定方法与确定应用中并行处理

    2022年9月20日
    0
  • jar包下载(全)

    jar包下载(全)转自:https://blog.csdn.net/meow_meow/article/details/78584696显示不出来请点击阅读更多作为初学者很多jar包不知道去哪里下载,给大家分享一个地址:这个网址是maven仓库的国内镜像地址:http://mvnrepository.com步骤图解:1.2.3….

    2022年5月15日
    96
  • DECLARE在SQL中的用法及相关等等

    DECLARE在SQL中的用法及相关等等:arrow:允许用户创建游标,用于在一个大的查询里面检索少数几行数据。变量是在批处理或过程的主体中用DECLARE语句声明的,并用SET或SELECT语句赋值。游标变量可使用此语句声明,并可用于其他与游标相关的语句。除非在声明中提供值,否则声明之后所有变量将初始化为NULL。Transact-SQL语法约定语法DECLARE{…

    2022年8月20日
    8
  • 使用kong时报 validate.nginx.ingress.kubernetes.io 错误解决办法

    使用kong时报 validate.nginx.ingress.kubernetes.io 错误解决办法

    2021年5月14日
    171

发表回复

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

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