java:基于弱引用(WeakReference)封装Supplier实现数据根据需要自动加载

本文介绍了Java中的弱引用机制,如何通过WeakReference实现对象的懒加载,当对象不再被需要时自动由垃圾收集器回收。作者还提供了WeakSupplier类的实现以及单元测试示例,展示了如何在实际项目中使用这种技术来优化内存管理。
摘要由CSDN通过智能技术生成

Java中的弱引用(WeakReference)是用来描述那些不会影响对象生命周期,但可能会在任何时候被垃圾收集器回收的对象引用。弱引用通常用于描述那些对象,它们非常重要,但又允许被自动回收。
在现实应用场景中,有些数据我们一开始会在初始时使用,之后使用的频率会很低,但它又比较大。如果使用普通的引用,会常驻内存占用资源。这时弱引用就派上用场了。
所以我们可以实现一个Supplier接口的类,封装一个弱引用实例。当要读取实例时,如果弱引用指向的实例不为null时就返回这个实例,当弱引用指向的对象为null时,执行加载,再返回。这样,就可以实现类似懒加载的方式按需获取数据,当数据不再被需要时,由GC自动回收。
基本实例逻辑的伪代码差不多就是这样:

	public T get() {
		if(null == weakReference) {
			synchronized (this) {
				if(null == weakReference) {
					// 当弱引用对象为null时 执行加载实例
					weakReference =....;
				}
			}
		}
		if(null == weakReference.get()){
			// 当弱引用指向的对象为null时,执行加载
			// 加载实例
			weakReference =....;
		}
		return weakReference.get();
	}

为了方便使用,我将这个逻辑封装了一个实现Supplier接口的WeakSupplier类。

实现代码

WeakSupplier.java

import java.lang.ref.WeakReference;

import com.google.common.base.Function;
import com.google.common.base.Supplier;
import static com.google.common.base.Preconditions.checkNotNull;

/**
 * {@link Supplier}弱引用实现,当弱引用失效时重新执行加载
 * @author guyadong
 *
 * @param <T>
 * @see 2.9.3
 */
public class WeakSupplier<T> implements Supplier<T> {
	private final  Supplier<T> supplier;
	private volatile WeakReference<T> weakReference;

	/**
	 * @param supplier
	 * @param immediateLoading 是否立即加载,为{@code true}立即调用 supplier
	 */
	public WeakSupplier(Supplier<T> supplier, boolean immediateLoading) {
		this.supplier = checkNotNull(supplier,"supplier is null");
		if(immediateLoading) {
			doGet();
		}
	}

	public WeakSupplier(Supplier<T> supplier) {
		this(supplier, true);
	}

	private void doGet() {
		weakReference = new WeakReference<>(checkNotNull(supplier.get(),"value from supplier %s is null",supplier));
	}
	@Override
	public T get() {
		if(null == weakReference) {
			synchronized (this) {
				if(null == weakReference) {
					doGet();
				}
			}
		}
		if(null == weakReference.get()){
			System.out.println("reload");
			doGet();
		}
		return weakReference.get();
	}

	/**
	 * 创建{@link WeakSupplier}实例
	 * @param <T>
	 * @param supplier
	 * @param immediateLoading 是否立即加载,为{@code true}立即调用 supplier
	 */
	public static <T> WeakSupplier<T> of(Supplier<T> supplier,boolean immediateLoading){
		if(supplier instanceof WeakSupplier) {
			return (WeakSupplier<T>) supplier;
		}
		return new WeakSupplier<>(supplier, immediateLoading);
	}
	/**
	 * 创建{@link WeakSupplier}实例(立即加载)
	 * @param <T>
	 * @param supplier
	 */
	public static <T> WeakSupplier<T> of(Supplier<T> supplier){
		return of(supplier,true);
	}
	public static<T>  Function<Supplier<T>, WeakSupplier<T>> weakSupplierFun(){
		return new Function<Supplier<T>, WeakSupplier<T>>(){
			@Override
			public WeakSupplier<T> apply(Supplier<T> input) {
				return of(input);
			}};
	}
}

单元测试及调用示例

WeakSupplierTest.java

import java.util.List;
import java.util.ArrayList;
import org.junit.Test;

import com.google.common.base.Supplier;

public class WeakSupplierTest {

	@Test
	public void testReload() throws InterruptedException {
		List<WeakSupplier<String>> suppliers = new ArrayList<>();
		for(int i=0;i<1000;++i) {
			final int num = i;
			suppliers.add(WeakSupplier.of(new Supplier<String>() {
				@Override
				public String get() {
					return "!!!!WEAK COUNT!!!!:"+ num;
				}
			}));
		}
		System.gc(); // 显式调用垃圾收集器
		int count = 0;
		while(count<suppliers.size()) {
			System.out.printf("%s\n", suppliers.get(count++).get());
			Thread.sleep(1000);
			
		}
	}

}

完整代码参见码云仓库:https://gitee.com/l0km/common-java/blob/master/common-base2/src/main/java/net/gdface/utils/WeakSupplier.java
测试代码:https://gitee.com/l0km/common-java/blob/master/common-base2/src/test/java/net/gdface/utils/WeakSupplierTest.java

  • 10
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

10km

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

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

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

打赏作者

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

抵扣说明:

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

余额充值