1

そのため、データベースからオブジェクトを取得するコードを書いています。これらのオブジェクトのいくつかはかなり重いです。それらをキャッシュする方法が必要です。これを行うために、.a で永続オブジェクトを参照します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ます。この時点で値hardRefが「アンカー」として使用され、必要に応じてデータベースからオブジェクトが引き出されます。nulllong

メモリが不足すると、SoftReferenceが収集される可能性があります。ただし、その前に、オブジェクトがまだデータベース側に存在するかどうかを確認する必要があります。そうでない場合は、ローカルに保持されているオブジェクトを に転送し、 をhardRefに設定SoftReferencenullます。

オブジェクトがまだデータベースにある場合は、参照オブジェクトを収集しても問題ありません。次にオブジェクトを呼び出す必要があるときは、longID を使用して取得します。(その後、誰かがそれを削除した場合は、例外をスローしても問題ありません)。

  1. これは機能しますか?言い換えれば、Holder.referent が null ではなく、データ競合なしで hardRef をその値に設定できると期待できますか?

  2. 重大なパフォーマンス ヒットが見られると期待できますか? ファイナライズには多少のオーバーヘッドがあることは承知していますが、物事をぎりぎりで停止させない限り、問題はないと思います。

finalize() は悪であり、決して使用すべきではないと誰もが言っているように見えるので、私はこの質問をしています。問題は、それ以外の方法が見当たらないことです。

4

0 に答える 0