在Java中,有没有办法判断引用是否正在维护到其他线程(或一般)中的对象?
考虑以下课程:
public class ResourcePool<TYPE>
{
private final Queue<Object> emptyLocks = new LinkedBlockingQueue<>();
private final Queue<TYPE> available = new LinkedBlockingQueue<>();
private final Queue<TYPE> claimed = new LinkedBlockingQueue<>();
public void add(TYPE resource)
{
available.add(resource);
}
public TYPE claim() throws InterruptedException
{
if (available.isEmpty())
{
Object lock = new Object();
synchronized (lock)
{
emptyLocks.add(lock);
lock.wait();
}
}
TYPE resource = available.poll();
claimed.add(resource);
return resource;
}
public void release(TYPE resource)
{
if (!claimed.remove(resource)) return;
available.add(resource);
Object lock = emptyLocks.poll();
if (lock != null) synchronized (lock) {lock.notify();}
}
}
这里的想法是多个线程可以声明/释放资源,这样两个线程在任何给定时刻都不会拥有相同的资源。但是如果一个线程忘记释放()一个资源会发生什么?更糟糕的是,如果线程调用release()然后继续使用资源做什么怎么办?
使用WeakReference类,可以判断何时不存在对给定对象的更强引用。然而,当发生这种情况时,该对象被垃圾收集并且它已经消失。 SoftReference可能会起作用,但在我们将资源重新放入&#34;可用&#34;之前,我们的资源仍然可能是GC。列表。
所以问题是:有没有办法跟踪这些资源是否仍然在使用?
理想情况下,线程可以声明()资源,只要他们想要使用它们,并且只要不再维护引用就会自动释放这些资源。我认为这将非常优雅,并且在其他情况下也很有用。
答案 0 :(得分:1)
答案很简单:没有
GC在VM全局级别和当前实现(至少在Hotspot中)工作,它不使用引用计数,更不用于参考跟踪。这意味着即使VM也不总是知道在任意时间点引用的是什么。
GC通常也是用于跟踪需要及时发布的内容的错误工具; GC可能很少运行(在极端情况下,GC可能会调整为每隔小时运行一次)。一旦拥有块范围结束,您可能希望您的资源可用于其他线程;要求与GC的松散处理大不相同。
你想要的是立即检测每个线程超出范围的事物。虽然这是一个很好的功能,但问题是它是否值得对其产生的性能影响。
您的资源示例和一个“忘记”在发布后释放/保留资源的线程是可以通过约定处理的事情:使用try-finally或者滥用try-with-resources块来确保生命周期得到妥善维护。
为了捕获资源的意外泄漏,您可以滥用最终结果;但是当资源最终确定时,它不能预测(并且你只能进行清理,不应该完成恢复资源;请参阅JLS关于最终确定)。
编辑:通过在资源中占用所有者,您可以在发布后使用资源轻松地防御对抗胭脂线程。然后,资源可以执行运行时检查调用线程确实是当前所有者。