【軟引用】--- 爲HashMap 增加軟引用功能

HashMap 是常用的數據結構,1.7是數組+鏈表,1.8是數組+紅黑樹,之前我寫過AVL樹的文章,過幾天寫一下紅黑樹的。

 

github:https://github.com/ai2101039/SoftHashMap

 

今天的主題是:給HashMap 增加軟引用功能。

 

也許有人想,我直接 HashMap 的 V 使其繼承軟引用不就可以了?我想說,你說的對,只是不全面。

 

一、適用場景

V所對應的對象數量衆多,可能會導致內存溢出。

 

二、非常重要

先看全代碼,然後從上往下讀代碼,讀完之後,看我最後的解釋圖,這樣就清楚了。

 

三、直接上代碼,代碼內把重點地方進行標註解答

/**
 * @author 高延榮
 * @date 2018/12/10 11:40
 * 描述: 具備軟引用功能的 HashMap
 */
public class SoftHashMap<K, V> extends HashMap<K, V> {

    /**
     * queue,軟引用標記隊列
     * <p>
     * ★★★★★★★ 解釋 ★★★★★★★
     * 當SoftNode中 Value 被回收時,SoftNode 對象會被放入 queue中,以表示當前SoftNode 中的Value不存在
     * 對我們的使用好處就是,我們讀取 queue 隊列,取出 SoftNode對象,取出其內部的 Key
     * 以便於 temp 通過 key remove
     */
    private ReferenceQueue<V> queue;
    /**
     * 真正的map對象
     * 1、temp 內部 封裝的 Node 強引用 K 和 SoftNode
     * 2、SoftNode 內部強引用K,弱引用真正的Value
     */
    private HashMap<K, SoftNode<K, V>> temp;

    public SoftHashMap() {
        queue = new ReferenceQueue<>();
        temp = new HashMap<>();
    }

    @Override
    public V get(Object key) {
        clearQueue();
        // 通過 key進行取值,如果爲null,返回null,否則返回 SoftNode 軟引用的值
        SoftNode softNode = temp.get(key);
        return softNode == null ? null : (V) softNode.get();
    }

    @Override
    public V put(K key, V value) {
        clearQueue();
        // 創建 SoftNode對象
        SoftNode softNode = new SoftNode(key, value, queue);
        // 返回key之前所對應的SoftNode對象,即oldSoftNode
        SoftNode oldSoftNode = temp.put(key, softNode);
        // 如果oldSoftNode爲null,就返回null,否則就返回 oldSoftNode所軟引用的 Value
        return oldSoftNode == null ? null : (V) oldSoftNode.get();
    }

    @Override
    public boolean containsKey(Object key) {
        clearQueue();
        return temp.containsKey(key);
    }

    @Override
    public V remove(Object key) {
        clearQueue();
        SoftNode<K, V> remove = temp.remove(key);
        return remove == null ? null : remove.get();
    }

    @Override
    public int size() {
        clearQueue();
        return temp.size();
    }

    /**
     * 通過軟引用隊列內的 SoftNode,獲取Key,然後temp 清除此 Key
     * @see ReferenceQueue poll()
     * poll() -- 類似於 stack 的pop(),移除並返回此對象
     */
    private void clearQueue() {
        SoftNode poll;
        while ((poll = (SoftNode) queue.poll()) != null) {
            temp.remove(poll.key);
        }
    }


    /**
     * 對V進行軟引用的類
     * @param <K> key,用於當 V 被回收後,temp 可以通過 key 進行移除
     * @param <V> Value,真正的值
     *
     *           傳入的queue,用於當Value被回收後,將 SoftNode對象放入 queue中,
     *           以便於表示 某 SoftNode對象中的Value 已經被收回了。
     */
    private class SoftNode<K, V> extends SoftReference<V> {
        K key;

        public SoftNode(K k, V v, ReferenceQueue queue) {
            super(v, queue);
            key = k;
        }
    }
}

我建議大家可以直接創建一個類去看。

四、畫圖解答

五、答疑

1、爲什麼SoftNode 需要傳入 K,和 ReferenceQueue

A:

傳入 queue 是爲了當 V 被回收後,將 SoftNode對象傳入到 queue中,以便於通知使用者,這個 SoftNode已經沒有Value了

傳入 K,是爲了我們的temp 可以通過 K 進行移除無效數據

 

2、爲什麼要使用函數  clearQueue()

    private void clearQueue() {
        SoftNode poll;
        while ((poll = (SoftNode) queue.poll()) != null) {
            temp.remove(poll.key);
        }
    }

A:

舉例,如果 從 K1 ~ K10 對應的 SoftNode 1 ~ SoftNode 10

SoftNode 1 ~ SoftNode 10 內部的 Value 均爲 null,即均被回收了。

那麼此時 temp 中的 K1 ~ K10 就應該被移除掉。

所以每次 put get 等函數 都會調用清除動作。

 

3、軟引用到底啥意思

    if(內存不足){
        v = null;
    }

 

 

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