在SoftReference的引用上重写finalize以保持数据存活是否有任何问题?

时间:2016-03-31 18:33:23

标签: java caching volatile finalize soft-references

所以我正在编写从数据库中提取对象的代码。其中一些对象非常大。我需要一种方法来缓存它们。为此,我引用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...
}

总而言之,当您最初从数据库中下拉对象时,会将其放入Holder,这是SoftReference的指示对象。此时hardRefnulllong值将用作“锚点”,以便在必要时从数据库中下拉对象。

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

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

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

  2. 我是否希望看到任何重大的表现?我知道敲定有一些头脑,但只要我不把事情搞砸,我想我们没事。

  3. 我问这个问题,因为每个人似乎都认为finalize()是邪恶的,我永远不应该使用它。问题是,我只是看不到任何其他方式。

0 个答案:

没有答案