WeakHashMap 源码分析

一、类图

       

二、源码分析

       a.  WeakHashMap 的 Key 是弱引用的,也就是 Key 放在 map 结构中不阻止对其进行垃圾回收

       b.  WeakHashMap 的 Value 是强引用,只有对应的 Key 被回收,才会回收

       c.  Value 不应直接或间接引用 Key,否则会阻止对 Key 的回收,一种处理方法是插入前弱化 Value 

            m.put(key, new WeakReference(value))

       d.  iterator 在 WeakHashMap 结构变化后会立即失败 ConcurrentModificationException,除非是迭代器执行 remove

       f.   初始容量是 16,容量必须是 2 的整数次幂,hashcode &(容量 - 1)正好是数组 index 下标

            2^4=16 , hashcode & 15 = hashcode & 1111 ==> 只取 hashcode 末尾几位作为 map 数组下标

            

       g.  最大容量 1 << 30 == 2^30 == 1073741824 ,最大容量必须是 2 的整数次幂,原因同上

       h.  默认装载因子 load factor 0.75f

        i.  内部 table 始终应该为 2 的整数次幂

        j.  内部使用一个整数变量 modCount 记录 WeakHashMap 结构变更次数,用于使迭代器快速失效

       k.  构造函数如果传入不是 2 的整数次幂的大小,构造函数会自动修正

            

        l.   Null 类型的 Key,其实用的是内部的一个 Object 对象

       m.  内置了一个 hash 函数,目的是二次处理 Key 对象的 hashcode,使得各位分布尽量均匀

             

       n.  WeakHashMap 的 size 不是直接返回的 size 变量值,先进行一次清理

            

       o.  当 put 后 size >= 阈值,table 扩大为原来的二倍,重新 hash

    public V put(K key, V value) {
        Object k = maskNull(key);
        int h = hash(k);
        Entry<K,V>[] tab = getTable();
        int i = indexFor(h, tab.length);

        for (Entry<K,V> e = tab[i]; e != null; e = e.next) {
            if (h == e.hash && eq(k, e.get())) {
                V oldValue = e.value;
                if (value != oldValue)
                    e.value = value;
                return oldValue;
            }
        }

        modCount++;
        Entry<K,V> e = tab[i];
        tab[i] = new Entry<>(k, value, queue, h, e);
        if (++size >= threshold)
            resize(tab.length * 2);
        return null;
    }

    void resize(int newCapacity) {
        Entry<K,V>[] oldTable = getTable();
        int oldCapacity = oldTable.length;
        if (oldCapacity == MAXIMUM_CAPACITY) {
            threshold = Integer.MAX_VALUE;
            return;
        }

        Entry<K,V>[] newTable = newTable(newCapacity);
        transfer(oldTable, newTable);
        table = newTable;

        /*
         * If ignoring null elements and processing ref queue caused massive
         * shrinkage, then restore old table.  This should be rare, but avoids
         * unbounded expansion of garbage-filled tables.
         */
        if (size >= threshold / 2) {
            threshold = (int)(newCapacity * loadFactor);
        } else {
            expungeStaleEntries();
            transfer(newTable, oldTable);   // 扩容的时候还可能发生缩容!!!
            table = oldTable;
        }
    }

       p.   使用内置的 eq 方法,判断 key 是否相等,AbstractMap 也是如此,都在 equals 基础上做了增强

       q.  Entry 都是静态内部类,AbstractMap 是 public 的,而此处是 private 的

        r.  Entry 继承了 WeakReference,关键代码,将 key 弱引用化,super(key, queue);

        Entry(Object key, V value,
              ReferenceQueue<Object> queue,
              int hash, Entry<K,V> next) {
            super(key, queue);
            this.value = value;
            this.hash  = hash;
            this.next  = next;
        }

             WeakReference  提供了 get() 方法获取 key,弱引用还在就能成功获取

             

       s.  关于 WeakReference,如果它所引用的对象没有其他 Strong Reference,在下次 GC 时就会对其进行回收

            因此,WeakHashMap 适合用作缓存系统,也就是说对象的创建删除很容易,但是占用内存比较大,

            删除的话不会对系统有较大影响(可以很快重建缺失内容),但是能有效减少内存占用,避免内存泄漏

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值