title: Are there any problems with overriding finalize on a referent of a SoftReference to keep data alive?
body: <p>So I am writing code that pulls down objects from the database. Some of these objects are pretty hefty. I need a way to cache them. To do this, I refer to the persistent object in a <code>SoftReference</code>.</p>
  
  <p>However, it is possible for outside forces to act upon the database and delete this object from the database without the current thread's knowledge. What I want to do is reduce the risk of losing the object if this happens and the <code>SoftReference</code> is collected.</p>
  
  <p>To that end, I have written this code</p>
  
  <pre><code>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&lt;Holder&gt; 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...
  }
  </code></pre>
  
  <p>So to summarize, when you pull down the object from the database initially, it is placed into a <code>Holder</code>, which is the referent of a <code>SoftReference</code>. <code>hardRef</code> would be <code>null</code> at this time and the <code>long</code> value would be used as an "anchor" to pull down the object from the database if necessary.</p>
  
  <p>Once memory gets tight, the <code>SoftReference</code> might be collected. However, before it does that, I want to to check to see if the object still exists database-side. If it does not, then I want to transfer the locally maintained object to <code>hardRef</code> and set the <code>SoftReference</code> to <code>null</code>.</p>
  
  <p>If the object IS still in the database, then we are okay with allowing the referent object to be collected. Next time we need to recall the object, we will use longID to go get it. (Mind you, if after that happens, someone has deleted it, then I'm okay with throwing an exception).</p>
  
  <ol>
  <li><p>Will this work? In other words, can I expect the Holder.referent to be non-null and to be able to set hardRef to that value without any kind of data-race?</p></li>
  <li><p>Would I expect to see any significant performance hits? I know finalize has some over-head, but so long as I don't bring things to a grinding halt, I think we're alright.</p></li>
  </ol>
  
  <p>I'm asking this question because everyone seems to say that finalize() is evil and that I should NEVER use it. The problem is, I just can't see any other way.</p>