そのため、データベースからオブジェクトを取得するコードを書いています。これらのオブジェクトのいくつかはかなり重いです。それらをキャッシュする方法が必要です。これを行うために、.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
が「アンカー」として使用され、必要に応じてデータベースからオブジェクトが引き出されます。null
long
メモリが不足すると、SoftReference
が収集される可能性があります。ただし、その前に、オブジェクトがまだデータベース側に存在するかどうかを確認する必要があります。そうでない場合は、ローカルに保持されているオブジェクトを に転送し、 をhardRef
に設定SoftReference
しnull
ます。
オブジェクトがまだデータベースにある場合は、参照オブジェクトを収集しても問題ありません。次にオブジェクトを呼び出す必要があるときは、longID を使用して取得します。(その後、誰かがそれを削除した場合は、例外をスローしても問題ありません)。
これは機能しますか?言い換えれば、Holder.referent が null ではなく、データ競合なしで hardRef をその値に設定できると期待できますか?
重大なパフォーマンス ヒットが見られると期待できますか? ファイナライズには多少のオーバーヘッドがあることは承知していますが、物事をぎりぎりで停止させない限り、問題はないと思います。
finalize() は悪であり、決して使用すべきではないと誰もが言っているように見えるので、私はこの質問をしています。問題は、それ以外の方法が見当たらないことです。