【发布时间】:2014-02-07 16:07:56
【问题描述】:
在一个程序中,我需要将弱引用存储在某个存储引擎(实际上是嵌入式 Prolog 数据库)中。为了使解释简单,可以将这种存储引擎(在本问题的上下文中)视为弱引用的集合。
我需要保证,一旦引用被回收,弱引用就会从存储引擎中收回。换句话说,如果 get() 方法已经返回 null,则应该无法从引擎访问弱引用。
我目前通过ReferenceQueue 实现了这一点。
以下代码通过添加cleanUp() 方法(调用从引擎中删除弱引用的清理任务)来扩展弱引用:
public class MyWeakRef<REF_TYPE> extends WeakReference<REF_TYPE> {
MyWeakRef(REF_TYPE referent, ReferenceQueue<REF_TYPE> referenceQueue, Runnable cleaningTask, ...) {
super(referent, referenceQueue);
this.cleaningTask = cleaningTask;
...
}
void cleanUp() {
cleaningTask.run();
}
...
}
下面的代码显示了如何在一个单独的线程中清理引用,该线程从 ReferenceQueue 获取回收的引用并调用它们的 cleanUp() 方法:
public class WeakReferencesCleaner extends Thread {
private static WeakReferencesCleaner referencesCleaner = new WeakReferencesCleaner(new ReferenceQueue<Object>());
public static WeakReferencesCleaner getWeakReferencesCleaner() {
return referencesCleaner;
}
public synchronized static void startWeakReferencesCleaner() {
if(!referencesCleaner.isAlive())
referencesCleaner.start();
}
private ReferenceQueue<?> referenceQueue;
public WeakReferencesCleaner(ReferenceQueue<?> referenceQueue, int priority) {
this.referenceQueue = referenceQueue;
this.setDaemon(true);
}
public ReferenceQueue<?> getReferenceQueue() {
return referenceQueue;
}
@Override
public void run() {
while(true) {
try {
MyWeakRef<?> ref = (JTermRef<?>) referenceQueue.remove();
try {
ref.cleanUp();
} catch(Exception e) {
...
}
} catch (InterruptedException e) {}
}
}
}
虽然在我的测试中这工作正常,但我在 WeakReference 类的文档中发现了以下内容:
假设垃圾收集器在某个时间点确定 对象弱可达的时间。到时候就会 原子地清除对该对象的所有弱引用......同时 时间或稍后的某个时间,它会将那些新清除的弱者排入队列 在引用队列中注册的引用。
因此,在引用失效和方法cleanUp() 执行之间,另一个线程可以查询引擎并仍然找到失效的引用。
我的问题是:如何在多线程上下文中保证我的引擎永远不会返回无效的引用?
【问题讨论】:
-
简短回答,你不能。您需要更改您的要求或使用其他设施。
-
如果您需要替代解决方案的建议,您必须提供有关您尝试解决的问题的更多详细信息。
-
嗨 @jtahlborn 你所说的使用“另一个设施”是什么意思?
-
@jtahlborn 我要解决的问题是实现嵌入在 Java 中的 Prolog 引擎,支持存储和操作(弱)引用。
-
“存储”是什么意思,弱引用指的是什么? prolog 引擎与任何事物有什么关系?
标签: java multithreading garbage-collection weak-references