所以我正在编写从数据库中提取对象的代码。其中一些物体非常重。我需要一种方法来缓存它们。为此,我指的是SoftReference
.
但是,外部力量有可能在当前线程不知情的情况下作用于数据库并从数据库中删除该对象。如果发生这种情况并SoftReference
收集到,我想要做的是降低丢失对象的风险。
为此,我写了这段代码
public class SoftDBObject
{
/** A hard reference to the wrapped persistable object. When the object
* is persisted in the database. this is null. */
// I made this "volatile", but I'm not sure if it needs to be. I figure
// if the finalizer thread needs to set this object, then the current
// thread should be made aware immediately.
protected volatile transient O hardRef;
/** A soft reference to the wrapped object. */
private transient SoftReference<Holder> softRef;
/** The unique ID number. */
protected transient long longID;
/** This class holds a referent. Upon garbage collection, it checks to
* see if the referent persistable is in the database. If not, then it
* transfers the wrapped referent value it contains to the hard
* reference in the outer class. This ensures that if an object is
* deleted from the database, the soft reference will not drop the
* object unexpectedly. */
class Holder
{
final O referent;
public Holder(final O referent)
{
this.referent=referent;
}
protected void finalize() throws Throwable
{
super.finalize();
if(softRef!=null)
{
// If the object is no longer persisted in the database, transfer
// the referent to a hard reference in the outer class.
// Otherwise, allow the soft reference to be reclaimed, along
// with the referent. We will only need to longID value to
// recall the object from the database if we need it in the
// future.
final O temp=refreshInternal(longID);
if(temp==null)
{
hardRef=referent;
softRef=null;
}
}
}
}
/** This method queries the database, finds the persisted object, and
* returns it. If the object was not found, then it returns null. */
private O refreshInternal(final long longID)
{
// it's not important...
return (O)refreshedObject;
}
// Some other non-important stuff...
}
总而言之,当您最初从数据库中拉下对象时,它被放入 aHolder
中,这是 a 的所指对象SoftReference
。hardRef
将null
在此时,并且该long
值将用作“锚”以在必要时从数据库中拉下对象。
一旦内存变得紧张,SoftReference
可能会被收集。但是,在此之前,我想检查该对象是否仍然存在于数据库端。如果没有,那么我想将本地维护的对象转移到hardRef
并将其设置SoftReference
为null
.
如果对象仍在数据库中,那么我们可以允许收集所指对象。下次我们需要召回对象时,我们将使用 longID 去获取它。(请注意,如果在那之后,有人删除了它,那么我可以抛出异常)。
这行得通吗?换句话说,我可以期望 Holder.referent 为非 null 并且能够在没有任何数据竞争的情况下将 hardRef 设置为该值吗?
我会期望看到任何显着的性能下降吗?我知道 finalize 有一些开销,但只要我不让事情陷入僵局,我认为我们没问题。
我问这个问题是因为每个人似乎都说 finalize() 是邪恶的,我永远不应该使用它。问题是,我只是看不到任何其他方式。