Java 覆盖SoftReference的引用对象以保持数据活动是否存在任何问题?

Java 覆盖SoftReference的引用对象以保持数据活动是否存在任何问题?,java,caching,volatile,finalize,soft-references,Java,Caching,Volatile,Finalize,Soft References,因此,我正在编写从数据库中提取对象的代码。其中一些物体相当大。我需要一种方法来缓存它们。为此,我在SoftReference中引用持久对象 但是,在当前线程不知情的情况下,外力可能会作用于数据库并从数据库中删除此对象。我想做的是,如果发生这种情况并且收集了SoftReference,则可以降低丢失对象的风险 为此,我编写了以下代码 public class SoftDBObject { /** A hard reference to the wrapped persistable objec

因此,我正在编写从数据库中提取对象的代码。其中一些物体相当大。我需要一种方法来缓存它们。为此,我在
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...
}
公共类SoftDBObject
{
/**对包装的持久对象的硬引用。当
*在数据库中持久化。这是空的*/
//我让它“不稳定”,但我不确定它是否需要。我想
//如果终结器线程需要设置此对象,则当前
//线程应立即通知。
受保护的挥发性瞬态O hardRef;
/**对包裹对象的软引用*/
专用瞬态软参考softRef;
/**唯一的ID号*/
保护瞬变长周期;
/**此类持有一个引用。在垃圾收集时,它会检查
*查看引用对象是否在数据库中是可持久的。如果不是,则
*将其包含的包装引用值传输到硬
*外部类中的引用。这可确保
*从数据库中删除,软引用将不会删除
*意外地拒绝*/
阶级持有者
{
最后O指代物;
公众持有人(最终参考)
{
this.referent=referent;
}
受保护的void finalize()抛出可丢弃的
{
super.finalize();
if(softRef!=null)
{
//如果对象不再在数据库中持久化,则传输
//外部类中硬引用的引用。
//否则,允许回收软引用,以及
//使用referent。我们只需要将值
//如果在数据库中需要对象,请从数据库中调用该对象
//未来。
最终O温度=刷新内部(纵向);
if(temp==null)
{ 
hardRef=参考物;
softRef=null;
}
}
}
}
/**此方法查询数据库,查找持久化对象,然后
*返回它。如果找不到对象,则返回null*/
私人O refreshInternal(最终长时间)
{
//这不重要。。。
返回(O)刷新对象;
}
//其他一些不重要的东西。。。
}
总而言之,当您最初从数据库中拉出对象时,它会被放置到
支架
,这是
软引用
的参照物<此时code>hardRef将为
null
,并且
long
值将用作“锚定”,以便在必要时从数据库中拉下对象

一旦内存紧张,可能会收集
SoftReference
。但是,在此之前,我想检查对象是否仍然存在于数据库端。如果没有,那么我想将本地维护的对象转移到
hardRef
,并将
SoftReference
设置为
null

如果对象仍然在数据库中,那么我们可以允许收集引用对象。下次我们需要回忆对象时,我们将使用longID去获取它。(请注意,如果发生这种情况后,有人删除了它,那么我可以抛出一个异常)

  • 这样行吗?换句话说,我能期望Holder.referent是非null的,并且能够在没有任何数据竞争的情况下将hardRef设置为该值吗

  • 我是否希望看到任何显著的性能影响?我知道finalize有些过头了,但只要我不让事情陷入停顿,我想我们没事


  • 我问这个问题是因为每个人似乎都说finalize()是邪恶的,我不应该使用它。问题是,我看不到任何其他方法。

    finalize()
    会造成巨大的性能损失。如果你期望有成千上万的这样的物体,你一定要避开它。即使没有这一点,我也可能更喜欢使用引用队列参数创建软引用,并使用它来检测对象何时进入收集队列。问题是(至少据我所知),当
    SoftReference
    到达
    ReferenceQueue
    时,调用
    get()
    将返回null。这意味着我将无法保存其中包含的数据。我认为只有
    PhantomReference
    才能做到这一点。至少我在
    SoftReference
    的文档中看不到任何说明
    get()
    将返回
    null
    的内容。为什么要在最后一分钟保留对没有其他引用的内容的引用?即使代码在技术上可行,这将是一个巨大而复杂的混乱局面,我将避免。如果一个包装在引用被丢弃之前没有被持久化,那么它就不应该被持久化
    finalize()
    在引用进入队列之前被调用,这意味着您无法从
    ReferenceQueue
    清理线程恢复引用对象。
    finalize()
    会造成巨大的性能损失。如果你期望有成千上万的这样的物体,你一定要避开它。即使没有这一点,我也可能更喜欢使用引用队列参数创建软引用,并使用它来检测对象何时进入收集队列。问题是(至少据我所知),当
    SoftReference
    到达
    ReferenceQueue
    时,调用
    get()
    将返回null。这意味着我将无法保存数据