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

来源:互联网 发布:平克弗洛伊德知乎 编辑:程序博客网 时间:2024/04/30 23:29
详见以下测试代码及其注释:

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 intSIZE= 1000;private double[]la= new double[SIZE];private Stringident;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 执行后将会回收对象 */@Testpublic 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");}@Testpublic 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 */@Testpublic 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 */@Testpublic 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 非常适合缓存应用 */@Testpublic 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, 这也正是它名字的由来 */@Testpublic 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 */@Testpublic 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());}@Testpublic 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());}}


参考:

http://www.iteye.com/topic/401478

http://zhang-xzhi-xjtu.iteye.com/blog/484934

http://zhang-xzhi-xjtu.iteye.com/blog/413159

原创粉丝点击