Есть ли проблемы с переопределением 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 для его получения. (Имейте в виду, если после этого кто-то удалил это, тогда я в порядке с исключением исключения).
Будет ли это работать? Другими словами, могу ли я ожидать, что Holder.referent будет ненулевым и сможет установить hardRef на это значение без какой-либо гонки данных?
Буду ли я ожидать каких-либо значительных успехов? Я знаю, что у финализатора есть некоторые накладные расходы, но пока я не доведу дело до упора, я думаю, что мы в порядке.
Я задаю этот вопрос, потому что все, кажется, говорят, что finalize() - это зло и что я никогда не должен его использовать. Проблема в том, что я просто не вижу другого пути.