【软引用】--- 为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;
    }

 

4、弱引用到底啥意思

    if(gc){
        v = null;
    }

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值