Java reference-aware cache

107 views Asked by At

I have memory-expensive objects, that sometimes come with identical content. I would like to cache them as long as they're referenced at least once, and evict from the cache if all referenced are destroyed. Is there a standard solution for that in Java?

Concretely, I would like to achieve something like the following:
ExpObject can be referenced by multiple instances of Entry, and each Entry can be contained in multiple collections. (any other references to ExpObject's don't need to be tracked).
When an Entry is created, we check whether there is already an equal ExpObject and if so, return the cached copy. Otherwise we cache and return the new object. The corresponding reference counter is incremented.
Finally, when all referenced to Entry are gone and it gets collected, the reference counter in ExpObject is decremented, and if it happened to be the last Entry that pointed to this ExpObject, then the ExpObject is evicted from the cache.
However, this solution relies on the finalize() method, that I've been told I shouldn't rely on.

class ExpObject {
    private final static Map<ExpObject, ExpObject> cache = new HashMap<>();
    private String longString; //stand-in for large content 
    private int referenced = 0;
    
    public static getExpObject(String content) {
        ExpObject newObject = new ExpObject(content);
        if (cache.containsKey(newObject)){
            ExpObject cachedCopy = cache.get(newObject);
            cachedCopy.referenced++;
            return cachedCopy;
        } else {
            newObject.referenced++;
            cache.put(newObject, newObject);
            return newObject;
        }
    }
    
    private ExpObject(String content){
        this.content = content;
    }
    
    public void decrementReference(){
        this.referenced--;
        if (this.referenced <= 0){
            cache.remove(this);
        }
    }
}

class Entry {
    private ExpObject expObject;
    
    public Entry(String content){
        expObject = ExpObject.getExpObject(content);
    }
    
    @Override
    protected void finalize(){
        expObject.decrementReference();
    }
}
0

There are 0 answers