你了解WeakHashMap吗

你了解WeakHashMap吗

WeakHashMap正是由于使用的是弱引用,因此它的对象可能被随时回收。在缓存场景下,由于内存是有限的,不能缓存所有对象,因此就需要一定的删除机制,淘汰掉一些对象。允许null键。

下面我们就来看看,WeakHashMap是如何实现这些功能。

Entry作用

//继承WeakReference
 private static class Entry<K,V> extends WeakReference<Object> implements Map.Entry<K,V> {
        V value;
        int hash;
        Entry<K,V> next;

        /**
         * Creates new entry.
         */
        Entry(Object key, V value, ReferenceQueue<Object> queue, int hash, Entry<K,V> next) {
            //这个super很关键,调用WeakReference的构造方法,使用key做referent
            super(key, queue);
            this.value = value;
            this.hash  = hash;
            this.next  = next;
        }

        @SuppressWarnings("unchecked")
        public K getKey() {
            return (K) WeakHashMap.unmaskNull(get());
        }

       //....其他省略
    }

和HashMap一样,WeakHashMap也是用一个Entry实体来构造里面所有的元素的,但是这个Entry却和HashMap的不同,他是弱引用。就是每当进行一次gc,你这个对象就会被清除,当然如果这个对象还存在着软引用或者强引用,就可能不会被清除。

ReferenceQueue 作用

    /**
     * Reference queue for cleared WeakEntries
     * 被清理的WeakEntries队列
     */
    private final ReferenceQueue<Object> queue = new ReferenceQueue<>();

queue是用来存放那些,被jvm清除的entry的引用,因为WeakHashMap使用的是弱引用,所以一旦gc,就会有key键被清除,所以会把entry加入到queue中。在WeakHashMap中加入queue的目的,就是为expungeStaleEntries所用。

expungeStaleEntries方法作用


    /**
     * Returns the table after first expunging stale entries.
     */
    private Entry<K,V>[] getTable() {
        expungeStaleEntries();
        return table;
    }

     /**
      * Expunges stale entries from the table.
      * 清理掉被GC的key对应Entries
      */
    private void expungeStaleEntries() {
        for (Object x; (x = queue.poll()) != null; ) {
            synchronized (queue) {
                @SuppressWarnings("unchecked")
                Entry<K,V> e = (Entry<K,V>) x;
                int i = indexFor(e.hash, table.length);

                Entry<K,V> prev = table[i];
                Entry<K,V> p = prev;
                while (p != null) {
                    Entry<K,V> next = p.next;
                    if (p == e) {
                        if (prev == e)
                            table[i] = next;
                        else
                            prev.next = next;
                        // Must not null out e.next;
                        // stale entries may be in use by a HashIterator
                        e.value = null; // Help GC 
                        size--;
                        break;
                    }
                    prev = p;
                    p = next;
                }
            }
        }
    }

实际上value的回收与key相比是有延迟的。key会被gc,而value,则是通过expungeStaleEntries赋值为null。

posted @ 2020-12-15 23:41  天宇轩-王  阅读(121)  评论(0编辑  收藏  举报