Есть ли проблемы с переопределением finalize для референта SoftReference для сохранения данных?

Поэтому я пишу код, который вытаскивает объекты из базы данных. Некоторые из этих объектов довольно здоровенные. Мне нужен способ их кеширования. Для этого я ссылаюсь на постоянный объект в 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 для его получения. (Имейте в виду, если после этого кто-то удалил это, тогда я в порядке с исключением исключения).

  1. Будет ли это работать? Другими словами, могу ли я ожидать, что Holder.referent будет ненулевым и сможет установить hardRef на это значение без какой-либо гонки данных?

  2. Буду ли я ожидать каких-либо значительных успехов? Я знаю, что у финализатора есть некоторые накладные расходы, но пока я не доведу дело до упора, я думаю, что мы в порядке.

Я задаю этот вопрос, потому что все, кажется, говорят, что finalize() - это зло и что я никогда не должен его использовать. Проблема в том, что я просто не вижу другого пути.

0 ответов

Другие вопросы по тегам