可通过SoftReference关联ReferenceQueue实现实时感知缓存回收:当JVM内存不足时GC回收软引用对象,其SoftReference实例自动入队,后台线程轮询队列即可获知并处理回收事件。
可以通过 softreference 关联 referencequeue,在对象被垃圾回收器清除时自动入队,从而实现对缓存对象回收的实时感知与响应。
SoftReference 与 ReferenceQueue 的协作机制
SoftReference 是一种“软可达”引用,当 JVM 内存不足时,GC 会优先回收其指向的对象。若在创建 SoftReference 时传入一个 ReferenceQueue,那么一旦该引用所指对象被回收,SoftReference 实例自身就会被自动加入到该队列中——注意:不是对象入队,而是引用对象(即 SoftReference 实例)入队。
这是实现“回收通知”的关键:轮询或阻塞式检查 ReferenceQueue,就能及时获知哪些缓存项已被释放。
构建可监控的软引用缓存容器
建议封装一个基于 Map + SoftReference + ReferenceQueue 的缓存类,核心要点包括:
- 使用 ConcurrentHashMap 存储 key → SoftReference
映射,保证线程安全 - 初始化时传入专用的 ReferenceQueue
,所有 SoftReference 都关联它 - 提供后台线程(或定时任务)持续调用 queue.poll() 或 queue.remove(0) 检查待处理引用
- 从队列取出的 SoftReference 可通过 get() 判断是否已清空(返回 null),再结合自定义逻辑(如记录日志、触发回调、更新统计)
避免常见陷阱
实际使用中容易忽略几个关键细节:
立即学习“Java免费学习笔记(深入)”;
- 不要仅靠 queue.isEmpty() 判断是否有回收发生——因为入队存在延迟,且可能有竞争;应采用循环 poll/remove + 空值检测
- SoftReference 实例本身需持有 key 信息,否则从队列取出后无法知道是哪个缓存项被回收;可在构造时扩展为继承 SoftReference 或包装成内部类,保存 key
- ReferenceQueue 不会自动清理已处理的引用,需手动取出并丢弃,否则会持续占用队列内存
- JDK 9+ 中 ReferenceQueue 的 remove(timeout) 更可靠,避免无限阻塞;JDK 8 及以前建议用带超时的 poll
简易示例片段
以下是一个最小可行监控结构示意:
private final ReferenceQueue<Object> queue = new ReferenceQueue<>();
private final Map<String, SoftReference<CachedData>> cache = new ConcurrentHashMap<>();
// 存入缓存(关联 queue)
cache.put(key, new SoftReference<>(new CachedData(), queue));
// 后台监控线程
new Thread(() -> {
while (!Thread.currentThread().isInterrupted()) {
try {
SoftReference<CachedData> ref = (SoftReference<CachedData>) queue.remove(100);
if (ref != null) {
// 此处可提取 key(需提前绑定)、记录回收、清理副作用等
System.out.println("Cache entry reclaimed: " + ref.key);
}
} catch (InterruptedException e) {
break;
}
}
}).start();


















