天天看點

一文帶你了解WeakHashMap

1. WeakHashMap的适用場景

大部分的緩存都需要占用記憶體,考慮到記憶體的有限性,并不能緩存所有的對象,此時就需要用到另類的集合,例如WeakHashMap,可以儲存一些對象的同時淘汰另一些對象,以此減少存儲成本。

2. 什麼是WeakHashMap

WeakHashMap,是在HashMap的基礎上多了Weak。表示這是一個弱引用的HashMap。

來看下WeakHashMap的類定義:

public class WeakHashMap<K,V>
    extends AbstractMap<K,V>
    implements Map<K,V> {
           

那WeakHashMap和HashMap有什麼差別呢?

3. WeakHashMap和HashMap的差別

在比較WeakHashMap和HashMap的差別之前,先來講一下弱引用(WeakReference)

關于弱引用

Java有4種引用,強引用(Strong),弱引用(Weak),軟引用(soft),虛引用(phantom)。

弱引用表示一個非必需的對象,強度低于軟引用,需要通過WeakReference類來間接引用目标對象。被弱引用關聯的對象隻能存活到下一次垃圾回收發生之前,當觸發垃圾回收時,無論目前記憶體是否足夠,都會回收掉隻被弱引用關聯的對象

注意:如果這個對象還被強引用所引用,那麼就不會被回收

簡單了解了弱引用之後,我們做一個

總結:

差別于HashMap的強鍵,WeakHashMap是弱鍵。

弱鍵的作用是随時可能被垃圾回收器回收。

4. WeakHashMap的實作原理

主要通過WeakReference和ReferenceQueue實作

來看下源碼:

/**
     * The entries in this hash table extend WeakReference, using its main ref
     * field as the key.
     */
    private static class Entry<K,V> extends WeakReference<Object> implements Map.Entry<K,V> {
        V value;
        final int hash;
        Entry<K,V> next;

        /**
         * Creates new entry.
         */
        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;
        }

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

        public V getValue() {
            return value;
        }

        public V setValue(V newValue) {
            V oldValue = value;
            value = newValue;
            return oldValue;
        }
           
  1. 建立WeakHashMap,将Entry添加到WeakHashMap中,通過數組table儲存Entry。
  2. 弱鍵在沒有被強引用引用的前提下,下一次GC将回收該弱鍵并添加到ReferenceQueue(queue)隊列中。
  3. 再一次操作WeakHashMap時,會先同步table和queue。table中儲存了全部的entry,queue中儲存被GC回收的entry;同步它們,就是删除table中被GC回收的鍵值對。
/**
     * Expunges stale entries from the table.
     */
    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;
                }
            }
        }
    }
           

WeakHashMap中的大部分操作都會調用expungeStaleEntries()這個方法,儲存被gc回收對象的queue會接收gc發送的回收消息,将queue中的key所對應的value指派null,幫助完成對Entry的回收工作。

繼續閱讀