I'm implementing a cache for Objects stored persistently. The idea is:
getObjectFromPersistence(long id); ///Takes about 3 seconds
getObjectFromCache(long id) //Instantly
And have a method: getObject(long id)
with the following pseudocode:
synchronized(this){ CustomObject result= getObjectFromCache(id) if (result==null){ result=getObjectFromPersistence(id); addToCache(result); } return result; }
But I need to allow the CustomObject to be collected by the garbage collector. Until now I was using an HashMap<Long,WeakReference<CustomObject>
for the implementation. The problem is that over the time the HashMap becomes filled of empty WeakReferences
.
I've checked WeakHashMap but there the keys are weak (and the values are still strong references) so having the longs with WeakReferences have no sense.
Whats the best solution for solving this problem? Is there some "inverse WeakHashMap" or something similar?
Thanks
WeakHashMap is an implementation of the Map interface that stores only weak references to its keys. Storing only weak references allows a key-value pair to be garbage-collected when its key is no longer referenced outside of the WeakHashMap. This class provides the easiest way to harness the power of weak references.
You can use a WeakHashmap to reduce the chance of a memory leak as a result of caching some object. The WeakHashMap will automatically remove entries whenever all references to the key are removed.
WeakHashMap can be used as in-memory cache, allowing keys to expire when they are weakly reachable. Unfortunately this class is not thread-safe. It's entirely possible that un-synchronized invocation of the WeakHashMap. get(Object) method will result in infinite busy waiting loop starving all other threads.
The purpose of the map is to translate exceptions and other tasks from one version to another. This map can get corrupted, which can cause threads to get stuck when executing the WeakHashMap method, which is not thread safe and can lock the entire application.
You can use the Guava MapMaker
for this:
ConcurrentMap<Long, CustomObject> graphs = new MapMaker() .weakValues() .makeMap();
You can even include the computation part by replacing makeMap()
with this:
.makeComputingMap( new Function<Long, CustomObject>() { public CustomObject apply(Long id) { return getObjectFromPersistence(id); } });
Since what you are writing looks a lot like a cache, the newer, more specialized Cache
(built via a CacheBuilder
) might be even more relevant to you. It doesn't implement the Map
interface directly, but provides even more controls that you might want for a cache.
You can refer to this for a detailed how to work for CacheBuilder and here is an example for fast access:
LoadingCache<Integer, String> cache = CacheBuilder.newBuilder() .maximumSize(100) .expireAfterWrite(10, TimeUnit.MINUTES) .build( new CacheLoader<Integer, String>() { @Override public String load(Integer id) throws Exception { return "value"; } } );
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With