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());
	}
}


参考:

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

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

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

评论 1 您还未登录,请先 登录 后发表或查看评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页

打赏作者

塘外人

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值