java中HashMap的另一面-Djdk.map.althashing.threshold


声明:本文转载自https://my.oschina.net/huangy/blog/1619144,转载目的在于传递更多信息,仅供学习交流之用。如有侵权行为,请联系我,我会及时删除。

1、参数jdk.map.althashing.threshold

使用方式:-Djdk.map.althashing.threshold=5

2、作用:当hash key 是String的时候,同时hash code 算法薄弱的情况,可以降低hash值的碰撞

代码中英文描述

     /**      * The default threshold of map capacity above which alternative hashing is      * used for String keys. Alternative hashing reduces the incidence of      * collisions due to weak hash code calculation for String keys.      * <p/>      * This value may be overridden by defining the system property      * {@code jdk.map.althashing.threshold}. A property value of {@code 1}      * forces alternative hashing to be used at all times whereas      * {@code -1} value ensures that alternative hashing is never used.      */

3、如何做到?

首先,我们都知道hashMap会根据key生成一个hash值,看代码如何生成一个key的hash值

final int hash(Object k) {     int h = hashSeed;     if (0 != h && k instanceof String) {         return sun.misc.Hashing.stringHash32((String) k);     }      h ^= k.hashCode();      // This function ensures that hashCodes that differ only by     // constant multiples at each bit position have a bounded     // number of collisions (approximately 8 at default load factor).     h ^= (h >>> 20) ^ (h >>> 12);     return h ^ (h >>> 7) ^ (h >>> 4); }


a、如果是String的话,就直接使用stringHash32生成hash值

b、直接调用Obejct的hashCode()方法,同时要和hashSeed 这个值进行异或操作

可以看出生成的hash值和hashSeed 这个值有着紧密的关系,但是这个值默认是0。也就是说不管HashMap存多少数据,hashSeed 都是不会变的,可以看出随着hashMap 的容量增大,hash碰撞的概率增大的可能性也就增大。如果hash值,碰撞很高的话,那么hashMap逐渐演化成链表,性能就急剧下降。

4、如何防止hashMap演化成链表?

static {     String altThreshold = java.security.AccessController.doPrivileged(         new sun.security.action.GetPropertyAction(             "jdk.map.althashing.threshold"));      int threshold;     try {         threshold = (null != altThreshold)                 ? Integer.parseInt(altThreshold)                 : ALTERNATIVE_HASHING_THRESHOLD_DEFAULT;          // disable alternative hashing if -1         if (threshold == -1) {             threshold = Integer.MAX_VALUE;         }          if (threshold < 0) {             throw new IllegalArgumentException("value must be positive integer.");         }     } catch(IllegalArgumentException failed) {         throw new Error("Illegal value for 'jdk.map.althashing.threshold'", failed);     }      ALTERNATIVE_HASHING_THRESHOLD = threshold; }


从代码看出jdk.map.althashing.threshold这个变量设置的值最终会存放在静态常量ALTERNATIVE_HASHING_THRESHOLD

final boolean initHashSeedAsNeeded(int capacity) {     boolean currentAltHashing = hashSeed != 0;     boolean useAltHashing = sun.misc.VM.isBooted() &&             (capacity >= Holder.ALTERNATIVE_HASHING_THRESHOLD);     boolean switching = currentAltHashing ^ useAltHashing;     if (switching) {         hashSeed = useAltHashing             ? sun.misc.Hashing.randomHashSeed(this)             : 0;     }     return switching; }


当hashMap扩大容量时,都是调用该方法。从代码可以看出,当数组容量超过,我们设定的值ALTERNATIVE_HASHING_THRESHOLD且是vm booted,同时 hashSeed==0的时候,hashSeed的值就是用随机量,而不是固定的等于0。这样就能降低碰撞,就能降低演化成链表概率。

代码具体过程:

当 hashSeed==0 则 currentAltHashing=false 当 capacity < Holder.ALTERNATIVE_HASHING_THRESHOLD 则currentAltHashing =false 结果: switching=false  当 hashSeed==0 则 currentAltHashing=false 当 capacity >= Holder.ALTERNATIVE_HASHING_THRESHOLD  则 currentAltHashing =true 结果: switching=true   当 hashSeed !=0 则 currentAltHashing=true 当 capacity < Holder.ALTERNATIVE_HASHING_THRESHOLD  则 currentAltHashing =false 结果: 当 switching=true  当 hashSeed !=0 则 currentAltHashing=true 当 capacity >= Holder.ALTERNATIVE_HASHING_THRESHOLD  则 currentAltHashing =true 结果: switching=false  回头再看代码,发现很巧妙

5、使用场景

很少场景会用的这个值,根据我自己测试的情况,默认配置情况就碰撞率相对来说已经可以接受了,分享这个主要是看看代码是怎么实现而已。

具体的测试类地址:https://github.com/tingliu9/basic-test/blob/master/src/test/java/com/github/tingliu/basic/test/Map2Test.java

6、总结:

-Djdk.map.althashing.threshold=-1:表示不做优化(不配置这个值作用一样)
-Djdk.map.althashing.threshold<0:报错

-Djdk.map.althashing.threshold=1:表示总是启用随机HashSeed
-Djdk.map.althashing.threshold>=0:便是hashMap内部的数组长度超过该值了就使用随机HashSeed,降低碰撞

jdk版本:jdk7_75

本文发表于2018年02月07日 00:32
(c)注:本文转载自https://my.oschina.net/huangy/blog/1619144,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如有侵权行为,请联系我们,我们会及时删除.

阅读 2541 讨论 0 喜欢 0

抢先体验

扫码体验
趣味小程序
文字表情生成器

闪念胶囊

万稳万当,不如一默。任何一句话,你不说出来便是那句话的主人,你说了出来,便是那句话的奴隶。

你要过得好哇,这样我才能恨你啊,你要是过得不好,我都不知道该恨你还是拥抱你啊。

直抵黄龙府,与诸君痛饮尔。

那时陪伴我的人啊,你们如今在何方。

不出意外的话,我们再也不会见了,祝你前程似锦。

快捷链接
网站地图
提交友链
Copyright © 2016 - 2021 Cion.
All Rights Reserved.
京ICP备2021004668号-1