WeakReference 4 - 代码实例

Java中WeakReference、WeakHashMap、SoftReference、ReferenceQueue的作用和使用场景:


package test;

import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertSame;
import static junit.framework.Assert.assertTrue;

import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.util.Map;
import java.util.WeakHashMap;

import org.junit.Test;

class VeryBig {
    private static final int SIZE = 1000;
    private double[] la = new double[SIZE];
    private String ident;

    public VeryBig(String id) {
        ident = id;
    }

    public VeryBig(String id, int s) {
        ident = id;
        la = new double[s];
    }

    public String toString() {
        return ident;
    }

    protected void finalize() {
        System.out.println("Finalizing " + ident);
    }
}

public class ReferencesTest {
    /**
     * Strong Reference<br>
     * 是 Java 的默认引用实现, 它会尽可能长时间的存活于 JVM 内, 当没有任何强引用指向对象时, GC 执行后将会回收对象
     */
    @Test
    public void strongReferenceNotGC() {
        System.out.println("start test strongReferenceNotGC");
        Object referent = new VeryBig("strongReferenceNotGC");

        /**
         * 通过赋值创建 StrongReference
         */
        Object strongReference = referent;

        assertSame(referent, strongReference);

        referent = null;
        System.gc();

        /**
         * 由于对象还存在引用,因此gc后,对象未被回收
         */
        assertNotNull(strongReference);
        System.out.println("end test strongReferenceNotGC");
    }

    @Test
    public void strongReferenceGC() throws InterruptedException {
        System.out.println("start test strongReferenceGC");
        Object referent = new VeryBig("strongReferenceGC");
        referent = null;
        System.gc();
        Thread.sleep(500);
        System.out.println("end test strongReferenceGC");
    }

    /**
     * WeakReference<br>
     * 顾名思义, 是一个弱引用, 当所引用的对象在 JVM 内不再有强引用时, GC后,弱引用被置成null,并回收所指的对象
     * 
     * @throws InterruptedException
     */
    @Test
    public void weakReference() throws InterruptedException {
        System.out.println("start test weakReference");
        WeakReference<Object> weakRerference = new WeakReference<Object>(new VeryBig(
                "weakReference"));
        System.gc();
        Thread.sleep(500);
        /**
         * weak reference 在 GC 后会被置成null,对象就可以被 回收了。。。
         */
        assertNull(weakRerference.get());
        System.out.println("end test weakReference");
    }

    /**
     * WeakHashMap<br>
     * 使用 WeakReference 作为 key, 一旦没有指向 key 的强引用, WeakHashMap 在 GC 后将自动删除相关的
     * entry
     * 
     * @throws InterruptedException
     */
    @Test
    public void weakHashMap() throws InterruptedException {
        Map<Object, Object> weakHashMap = new WeakHashMap<Object, Object>();
        Object key = new VeryBig("weakHashMap key");
        Object value = new Object();
        weakHashMap.put(key, value);

        assertTrue(weakHashMap.containsValue(value));

        key = null;
        System.gc();
        /**
         * 等待无效 entries 进入 ReferenceQueue 以便下一次调用 getTable 时被清理
         */
        Thread.sleep(1000);

        /**
         * 一旦没有指向 key 的强引用, WeakHashMap 在 GC 后将自动删除相关的 entry
         */
        assertFalse(weakHashMap.containsValue(value));
    }

    /**
     * SoftReference<br>
     * 与 WeakReference 的特性基本一致, 最大的区别在于 SoftReference会尽可能长的保留引用,不会在GC时就回收对象,而是直到
     * JVM 内存不足时才会被回收(虚拟机保证), 这一特性使得 SoftReference 非常适合缓存应用
     */
    @Test
    public void softReference() {
        SoftReference<Object> softRerference = new SoftReference<Object>(new VeryBig(
                "softReference"));

        assertNotNull(softRerference.get());

        System.gc();

        /**
         * soft references 只有在 jvm OutOfMemory 之前才会被回收, 所以它非常适合缓存应用
         */
        assertNotNull(softRerference.get());

        // make oom....
        int i = 0;
        while (true) {
            try {
                ++i;
                new VeryBig("oom ", 10000000);
            } catch (Throwable e) {
                System.out.println("OOM after " + i + " times");
                e.printStackTrace();
                break;
            }
        }

        assertNull(softRerference.get());
    }

    /**
     * PhantomReference<br>
     * Phantom Reference(幽灵引用) 与 WeakReference 和 SoftReference 有很大的不同, 因为它的
     * get() 方法永远返回 null, 这也正是它名字的由来
     */
    @Test
    public void phantomReferenceAlwaysNull() {
        ReferenceQueue<Object> q = new ReferenceQueue<Object>();
        PhantomReference<Object> phantomReference = new PhantomReference<Object>(
                new VeryBig("phantomReferenceAlwaysNull"), q);

        /**
         * phantom reference 的 get 方法永远返回 null
         */
        assertNull(phantomReference.get());

        assertNull(q.poll());
        System.gc();
        assertNull(q.poll());
    }

    /**
     * RererenceQueue<br>
     * 当一个 WeakReference 开始返回 null 时, 它所指向的对象已经准备被回收, 这时可以做一些合适的清理工作. 将一个
     * ReferenceQueue 传给一个 Reference 的构造函数, 当对象被回收时, 虚拟机会自动将这个weak ref插入到
     * ReferenceQueue 中, WeakHashMap 就是利用 ReferenceQueue 来清除 key 已经没有强引用的
     * entries
     * 
     * @throws InterruptedException
     */
    @Test
    public void referenceQueueWithWeakReference() throws InterruptedException {
        Object referent = new VeryBig("referenceQueueWithWeakReference");
        ReferenceQueue<Object> referenceQueue = new ReferenceQueue<Object>();
        Reference<Object> ref = new WeakReference<Object>(referent, referenceQueue);

        assertFalse(ref.isEnqueued());
        Reference<? extends Object> polled = referenceQueue.poll();
        assertNull(polled);

        referent = null;
        System.gc();

        assertTrue(ref.isEnqueued());
        Reference<? extends Object> removed = referenceQueue.remove();
        assertNotNull(removed);
        assertSame(ref, removed);
        assertNull(removed.get());
    }

    @Test
    public void referenceQueueWithSoftReference() throws InterruptedException {
        Object referent = new VeryBig("referenceQueueWithWeakReference");
        ReferenceQueue<Object> referenceQueue = new ReferenceQueue<Object>();
        Reference<Object> ref = new SoftReference<Object>(referent, referenceQueue);

        assertFalse(ref.isEnqueued());
        Reference<? extends Object> polled = referenceQueue.poll();
        assertNull(polled);

        referent = null;
        // make oom....
        try {
            new VeryBig("oom ", 100000000);
        } catch (Throwable e) {

        }
        assertTrue(ref.isEnqueued());
        Reference<? extends Object> removed = referenceQueue.remove();
        assertNotNull(removed);
        assertSame(ref, removed);
        assertNull(removed.get());
    }
}

你可能感兴趣的:(java,SoftReference,WeakReference)