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


相关推荐

  • 微信公众号无法抓包 提示请在微信客户端打开链接

    微信公众号无法抓包 提示请在微信客户端打开链接最近有一个需求是测试公司公众号中某个需要鉴权接口的性能。首先就是需要对该接口进行抓包,根据以前写过的一篇文章,我们可以过使用Fiddler对微信PC客户端抓包来获取接口信息。使用fiddler抓包微信公众号和小程序当我在微信PC端点击需要鉴权的公众号页面时弹出“请在微信客户端打开链接”OhMyGod!我的第一直觉是微信PC端升级所致(因为之前测试时没有出现过这个问题),check一下版本是:最新的3.5.046这个问题怎么搞?百度吧!关键词是什么呢?抱着试试看的态度搜索“…

    2022年5月10日
    74
  • 《跟菜鸟学Cisco UC部署实战》-上线了(线下培训班开班,见百度云)

    《跟菜鸟学Cisco UC部署实战》-上线了(线下培训班开班,见百度云)

    2021年9月16日
    59
  • Unity键盘钩子[通俗易懂]

    Unity键盘钩子[通俗易懂]http://blog.csdn.net/qq452626100/article/details/52398830privatestaticintKeyboardHookProc(intnCode,Int32wParam,IntPtrlParam){ if(nCode==HC_ACTION ) { varkc=(KeyCode)(wParam+97-65)

    2022年5月28日
    49
  • SpringMVC日期格式化

    SpringMVC日期格式化一、关于SpringMVC日期的格式化大概可分为四点1.@ResponseBody方式返回json的日期格式化2.ajax方式返回json的日期格式化3.数据保存时String转Date4.页面展示时,Date转固定格式的String二、配置实现日期格式化1.@ResponseBody方式返回json的日期格式化配置…

    2022年6月7日
    116
  • c#中高效的excel导入sqlserver的方法

    将oledb读取的excel数据快速插入的sqlserver中,很多人通过循环来拼接sql,这样做不但容易出错而且效率低下,最好的办法是使用bcp,也就是System.Data.SqlClient.S

    2021年12月27日
    36
  • np.astype()

    np.astype()1.作用:就是转换numpy数组的数据类型举个例子arr=np.arange((10))print(arr,arr.dtype,sep=”\n”)===================================[0123456789]int32#可以看到,他的数据类型为int32np.astype()arr=arr.astype(“f…

    2022年6月10日
    49

发表回复

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

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