基於源碼的Java集合框架學習⑨ WeakHashMap

類 WeakHashMap<K,V>

以弱鍵 實現的基於哈希表的 Map。在 WeakHashMap 中,當某個鍵不再正常使用時,將自動移除其條目。更精確地說,對於一個給定的鍵,其映射的存在並不阻止垃圾回收器對該鍵的丟棄,這就使該鍵成爲可終止的,被終止,然後被回收。丟棄某個鍵時,其條目從映射中有效地移除,因此,該類的行爲與其他的 Map 實現有所不同。

null 值和 null 鍵都被支持。該類具有與 HashMap 類相似的性能特徵,並具有相同的效能參數初始容量 和加載因子。

像大多數集合類一樣,該類是不同步的。可以使用 Collections.synchronizedMap 方法來構造同步的 WeakHashMap。

WeakHashMap 類的行爲部分取決於垃圾回收器的動作,所以,幾個常見的(雖然不是必需的)Map 常量不支持此類。因爲垃圾回收器在任何時候都可能丟棄鍵,WeakHashMap 就像是一個被悄悄移除條目的未知線程。特別地,即使對 WeakHashMap 實例進行同步,並且沒有調用任何賦值方法,在一段時間後 size 方法也可能返回較小的值,對於 isEmpty 方法,返回 false,然後返回 true,對於給定的鍵,containsKey 方法返回 true 然後返回 false,對於給定的鍵,get 方法返回一個值,但接着返回 null,對於以前出現在映射中的鍵,put 方法返回 null,而 remove 方法返回 false,對於鍵集、值集、項集進行的檢查,生成的元素數量越來越少。

WeakHashMap 中的每個鍵對象間接地存儲爲一個弱引用的指示對象。因此,不管是在映射內還是在映射之外,只有在垃圾回收器清除某個鍵的弱引用之後,該鍵纔會自動移除。

源碼

相較於HashMap,WeakHashMap內部多了一個成員:

    // queue保存的是“已被GC清除”的“弱引用的鍵”。
    // 弱引用和ReferenceQueue 是聯合使用的:如果弱引用所引用的對象被垃圾回收,
    // Java虛擬機就會把這個弱引用加入到與之關聯的引用隊列中
    private final ReferenceQueue<Object> queue = new ReferenceQueue<>();

對應添加了一個方法,將queue中已經保存的被GC清除的弱引用的鍵移出Map:

    private void expungeStaleEntries() {
    	//遍歷queue
        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;
                // 移出Entry的單向鏈表
                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;
                }
            }
        }
    }

在其內部的getTable、resize、size方法中會直接調用這個方法,而這幾個方法又會被其他方法所調用,所以就會出現在連續調用兩次同樣的方法時會得到不同的結果的現象。

與HashMap的比較

HashMap的key是對實際對象的強引用,而WeakHashMap中的key弱引用(WeakReference),弱引用的特性是:當gc線程發現某個對象只有弱引用指向它,那麼就會將其銷燬並回收內存。

若WeakHashMap裏面的key只有map本身引用時,gc就會將key指向的對向進行回收,同時這個“弱鍵”也會被添加到queue隊列中,等待內部將key對應的Entry清除掉。

應用場景

WeakHashMap常常會被應用於緩存,因爲緩存中的數據丟失是可以重新加載的,使用WeakHashMap就可以保證緩存中的數據都是被引用的,減少內存壓力。例如tomcat的源碼裏,實現緩存時就用到了WeakHashMap。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章