努力的小胖学习记录(六)----------HashMap优化的两个重要指标

探讨HashMap中capacity和loadFactor的重要性,如何根据应用场景调整这两个参数以减少hash冲突,提升性能。包括初始化容量的选择及负载因子的设定。

capacity和loadFactor

相信大家和我一样,最开始的时候和我对这两个指标并不陌生,毕竟两个指标是很容易理解的指标,但是是否很多和我一样,并没有想过对于一个map,他应该设置多大呢,我想大家估计肯定只是和我一样,简单的new一个,然后其它的工作全部交给map自己处理。那下面分享一下我这次新学习到的东西。

  • capacity
    之前我一直以为这个和map的size是同一个,但实际上这个值指定的是Node[] table的length,默认为16(这个值一定是为2的指数,方便取模定桶),而size是map中k-v键值对的数量。而扩容时判断的是size大小,而不是桶占用的数量,所以可能存在只占用了一个桶就开始扩容的情况,而这个时候急需要考虑自己的hashCode方法是否写的合理,所以在一些已知最大容量的srcMap时,我们可以考虑一次性初始化到位,这样既可以避免扩容,也可以减少hash冲突。下面是一些常见的处理方式:
  • Map map = new HashMap(srcMap.size()),这可能是大部分人的情况,但是肯定是不对的,这样有25%的概率会引起一次扩容。
  • Map map = new HashMap( 2* srcMap.size()),虽然比较粗暴,但这个是thrift的处理方式,唯一的缺点就是有点浪费空间
  • Map map = new HashMap((int) ((float) srcMap.size()/ 0.75F + 1.0F)),这个是Guava的做法,其中0.75F是默认的负载因子(loadFactor),这样寻找了确保一定不扩容时最小的容量。
    具体使用上面的哪一种,大家可以根据自己的实际情况选择。
  • loadFactor
    这个指标的名称为负载因子,表示当前HashMap最大能承受的size/capacity比例值,默认为0.75F。它直接影响到hashMap的另外一只属性threshold,threshold = capacity * loadFactor,所以threshold就是HashMap能承受的最大的size,当size超过threshold时,就会进行一次resize(扩容,这个很费时间,基本是对之前的元素挨个进行put操作),所以这个参数直接控制了扩容的时机,如果你当前的hashMap的hash冲突比较严重的时候,可以考虑将这个值设定小一点,可以提前扩容,这样虽然会增加put的时间,但是后面的get时候会更快,毕竟HashMap的定桶是很快的,主要时间还是浪费在链表的遍历上。
  • 总结
    上面讲了两个关于HashMap性能上很重要的两个指标,但是他两的目标都是一致的(减少hash冲突),最终的体现上都是容量的控制,那我们具体看下我们在工作中,应该怎么提升性能呢,个人建议如下几个原则:
  1. 在最大容量已知的情况下,一定避免扩容,尽量避免hash冲突,具体hashCode写重写规则可以参看我的上篇博文HashCode和equals。如果解决不了hash冲突的话,那你们在选择上就应该放弃hashMap
  2. 如果容量不可控的情况下并且key又是无法预估的话,你可以考虑降低你的loadFactor,建议是0.5-0.25,具体可以根据你的key的hash来设置
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值