Java弱引用之硬核复用机制

2020-04-13  本文已影响0人  风逝_c609

弱引用不是回收了吗?怎么还复用???下面咱们来一探究竟

1. 弱引用的常规使用

class Resource {
    Object data;

    public Resource(Object data) {
        this.data = data;
    }

    public Object getData() {
        return data;
    }
}

写代码用弱引用测试一把

    @Test
    public void testWeakFirst() {
        Resource resource = new Resource("data can re-use");
        WeakReference<Resource> weakReference = new WeakReference(resource);

        System.out.println("before gc");
        System.out.println("resource = " + resource);
        System.out.println("weakRef = " + weakReference.get());

        System.out.println("after gc");
        resource = null;
        System.gc();
        System.out.println("resource = " + resource);
        System.out.println("weakRef = " + weakReference.get());
    }

Run一把毫无悬念的结果

before gc
resource = team.opay.pay.Resource@484b61fc
weakRef = team.opay.pay.Resource@484b61fc
after gc
resource = null
weakRef = java.lang.ref.WeakReference@45fe3ee3
weakRef.get = null

Process finished with exit code 0

常规弱引用使用测试结论

2. 扩展WeakReference

2.1 简单扩展(不使用引用队列)
class ReuseWeakReferenceI extends WeakReference<Resource> {

    private String key;
    private Object source;

    public ReuseWeakReferenceI(String key, Resource referent) {
        super(referent);
        /**
         * 这里为什么是Resource的data字段呢?
         * 因为get方法毫无悬念的为空 可以尝试引用一下起内部的变量
         */
        this.source = referent.getData();
        this.key = key;
    }

    public Object getSource() {
        return source;
    }

    public String getKey() {
        return key;
    }

    public void reset() {
        this.key = null;
        this.source = null;// 让gc尽快回收
        clear();
    }
}

测试代码如下

    @Test
    public void testWeakSecond() {
        Resource resource = new Resource("data can re-use");
        ReuseWeakReferenceI weakReference = new ReuseWeakReferenceI("", resource);

        System.out.println("before gc");
        System.out.println("resource = " + resource);
        System.out.println("weakRef = " + weakReference.get());

        System.out.println("after gc");
        resource = null;
        System.gc();
        System.out.println("resource = " + resource);
        System.out.println("weakRef = " + weakReference);
        System.out.println("weakRef.get = " + weakReference.get());
        System.out.println("weakRef.get = " + weakReference.getSource());
    }

继续Run

before gc
resource = team.opay.pay.Resource@484b61fc
weakRef = team.opay.pay.Resource@484b61fc
after gc
resource = null
weakRef = team.opay.pay.ReuseWeakReferenceI@45fe3ee3
weakRef.get = null
weakRef.data = data can re-use

2.1无引用队列测试结论
-WeakReference引用在,其内部强引用也就在

2.2 扩展(使用引用队列)
class ReuseWeakReference extends WeakReference<Resource> {

    private String key;
    private Object source;

    public ReuseWeakReference(String key, Resource referent, ReferenceQueue<? super Resource> q) {
        super(referent, q);
        /**
         * 这里为什么是Resource的data字段呢?
         * 因为get方法毫无悬念的为空 可以尝试引用一下起内部的变量
         */
        this.source = referent.getData();
        this.key = key;
    }

    public Object getSource() {
        return source;
    }

    public String getKey() {
        return key;
    }

    public void reset() {
        this.key = null;
        this.source = null;// 让gc尽快回收
        clear();
    }
}

测试代码

@Test
    public void testLast() {
        String key = "sourceKey";
        Resource resource = new Resource("data can re-use");
        ReferenceQueue<Resource> referenceQueue = new ReferenceQueue<>();
        ReuseWeakReference weakReference = new ReuseWeakReference(key, resource, referenceQueue);
        Map<String, ReuseWeakReference> cache = new HashMap<>();
        cache.put(key, weakReference);

        System.out.println("before call gc");
        System.out.println("resource = " + resource);
        System.out.println("weakRef = " + weakReference.get());

        resource = null;
        System.gc();
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("after call gc");
        System.out.println("resource = " + resource);
        System.out.println("weakRef = " + weakReference.get());
        Reference reference;
        while ((reference = referenceQueue.poll()) != null) {
            ReuseWeakReference reuse = (ReuseWeakReference)reference;
            System.out.println("weakCacheMap size(before remove) = " + cache.size());
            cache.remove(reuse.getKey());
            System.out.println("weakCacheMap size(after remove) = " + cache.size());
            System.out.println("weakRef.queue reuse value = " + reuse.getSource());
        }
    }

运行结果

before call gc
resource = team.opay.pay.Resource@484b61fc
weakRef = team.opay.pay.Resource@484b61fc
after call gc
resource = null
weakRef = null
weakCacheMap size(before remove) = 1
weakCacheMap size(after remove) = 0
weakRef.queue ref.data (in memory) = data can re-use

2.2使用引用队列扩展测试结论

3. Andorid Glide实践

Glide ActiveResources之弱引用复用实践篇
当检测到正在使用的缓存不在使用时,有如下复用处理

上一篇下一篇

猜你喜欢

热点阅读