zoukankan      html  css  js  c++  java
  • HashMap的hashSeed的问题

    final boolean initHashSeedAsNeeded(int capacity) {
          //通过上面的过程,我们知道了currentAltHashing =false
            boolean currentAltHashing = hashSeed != 0;
           //useAltHashing = false
            boolean useAltHashing = sun.misc.VM.isBooted() &&
                    (capacity >= Holder.ALTERNATIVE_HASHING_THRESHOLD);
         // false ^ false 结果为false,switching为false
            boolean switching = currentAltHashing ^ useAltHashing;
            if (switching) {
                hashSeed = useAltHashing
                    ? sun.misc.Hashing.randomHashSeed(this)
                    : 0;
            }
            //返回false
            return switching;
        }
    

    —–本文只针对1.7版本的HashMap所讲解.

    我们知道了HashMap生成hash码的时候会涉及到hashSeed的问题,

        public V put(K key, V value) {
    
            if (table == EMPTY_TABLE) {
                inflateTable(threshold);
            }
            if (key == null)
                return putForNullKey(value);
                //对key生成hash码
            int hash = hash(key);
            int i = indexFor(hash, table.length);
            for (Entry<K,V> e = table[i]; e != null; e = e.next) {
                Object k;
                if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                    V oldValue = e.value;
                    e.value = value;
                    e.recordAccess(this);
                    return oldValue;
                }
            }
    
            modCount++;
            addEntry(hash, key, value, i);
            return null;
        }

    这里对key进行生成hash码,它是怎么生成的呢?我们看下面的代码:

    transient int hashSeed = 0;
    
    final int hash(Object k) {
            int h = hashSeed;
            if (0 != h && k instanceof String) {
                return sun.misc.Hashing.stringHash32((String) k);
            }
    
            h ^= k.hashCode();
            h ^= (h >>> 20) ^ (h >>> 12);
            return h ^ (h >>> 7) ^ (h >>> 4);
        }

    我们这里一步一步来解释,首先hashSeed怎么来的?它是HashMap的属性,在HashMap初始化时已经为0,但是我们在执行inflateTable方法时执行了initHashSeedAsNeeded方法这里面对hashSeed又执行了一次赋值操作,我们来代码:

        private void inflateTable(int toSize) {
            // Find a power of 2 >= toSize
            int capacity = roundUpToPowerOf2(toSize);
    
            threshold = (int) Math.min(capacity * loadFactor, MAXIMUM_CAPACITY + 1);
            table = new Entry[capacity];
            initHashSeedAsNeeded(capacity);
        }
    
        //hashSeed在这个方法里面又进行了一次赋值操作,为了让读者了解的更多,我尽量做的详细一点.
        final boolean initHashSeedAsNeeded(int capacity) {
        //当我们初始化的时候hashSeed为0,0!=0 这时为false.
            boolean currentAltHashing = hashSeed != 0;
            //isBooted()这个方法里面返回了一个boolean值,我们看下面的代码
            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;
        }

    sun.misc.VM类的代码如下:

        private static volatile boolean booted = false;
        public static boolean isBooted() {
            return booted;
        }

    这里返回的是booted 的值,但是booted 默认为false,但是我们不知道VM启动的时候是否对它又赋了新值,怎么办呢?我们可以用一个土办法来测试如下:这里写图片描述
    我们可以看到在Map执行前booted的值为true,然而我们HashMap执行的时候并没有给它赋值,所以它为true,然后我们比较后面的条件看看,我们看见要拿初始容量比较Holder.ALTERNATIVE_HASHING_THRESHOLD,但是我们不知道这个为多少.看代码.

        static final int ALTERNATIVE_HASHING_THRESHOLD_DEFAULT = Integer.MAX_VALUE;//这里为2147483647,它是HashMap的属性,初始化的时候就已赋值
        //Holder这个类是HashMap的子类,
         private static class Holder {
         //这里定义了我们需要的常量,但是它没赋值,我们看看它是怎么赋值的?
            static final int ALTERNATIVE_HASHING_THRESHOLD;
    
            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;
            }
        }

    我们通过代码看到ALTERNATIVE_HASHING_THRESHOLD来自threshold,threshold哪里呢?看上面得知来自判断条件里面.那我们就来看看判断条件altThreshold,altThreshold来自一个本地方法,我们还是用老方法,看看它的值为什么.

        @CallerSensitive
        public static native <T> T doPrivileged(PrivilegedAction<T> action);

     通过上面的流程以后,我们知道hashSeed 并没有重新赋值,最终hashSeed的值为0;

  • 相关阅读:
    labview事件结构
    20180105关于课题所用的labview的改进随笔
    同步FIFO与异步FIFO
    20180110labview串口传输实时显示相关内容
    labview相关内容
    科技英文写作之连词大全
    t-检验
    AngularJS -- 表单验证
    AngularJS -- 过滤器
    AngularJs -- 表达式
  • 原文地址:https://www.cnblogs.com/zouhong/p/13545444.html
Copyright © 2011-2022 走看看