Weak and concurrent hash map for caching

Hello,

I have written a very simple cache class with both weakness and concurrency benefits. This class is intended to be used as a weak cache in "hot redeploy" capable servers (JBoss or any other).

My implementation uses the (problematic) "double-check" pattern with a reentrant lock and encapsulates a WeakHashMap with WeakReference values (to avoid circular key/value references). Here is the code:

publicinterface ValueCreator<V>{

public V create();

}

publicclass WeakCache<K, V>{

privatefinal Lock lock =new ReentrantLock();

privatefinal Map<K, WeakReference><V>> weakMap;

public WeakCache(){

this(16);

}

public WeakCache(int initialCapacity){

this(initialCapacity, 0.75F);

}

public WeakCache(int initialCapacity,float loadFactor){

weakMap =new WeakHashMap<K, WeakReference><V>>(initialCapacity, loadFactor);

}

public V get(K key, ValueCreator<V> creator){

WeakReference<V> ref = weakMap.get(key);

if (ref ==null){

lock.lock();

try{

ref = weakMap.get(key);

if (ref ==null){

ref =new WeakReference<V>(creator.create());

weakMap.put(key, ref);

}

}finally{

lock.unlock();

}

}

return ref.get();

}

One usage of this cache is for session ejb3 lookup:

...

privatestaticfinal WeakCache<Class, Object> LOOKUP_CACHE =new WeakCache<Class, Object>();

...

publicstatic <T> T lookup(final Class<T> serviceClass){

T service = (T)LOOKUP_CACHE.get(serviceClass,

new ValueCreator<Object>(){

public T create(){

String lookup ="myapp/" + serviceClass.getSimpleName() +"/local";

try{

return (T)(new InitialContext()).lookup(lookup);

}catch (NamingException e){

thrownew RuntimeException("Could not lookup EJB " + serviceClass +": " + lookup, e);

}

}

}

);

return service;

}

...

2 questions:

1. Is there any issue with concurrent access to this cache ?

2. What happens exactly when the garbage collector wants to free memory with a map with both weak keys and values ?

Some limited tests show that the behavior of this cache fits my needs: the lookup cache is cleared on redeploy and it keeps its key/values pairs otherwise.

Thanks for any comments.

Message was edited by:

fwolff999

[4863 byte] By [fwolff999a] at [2007-11-27 2:27:45]
# 1
Your using DCL which is not thread safe and you know this, so what do you want to know beyond that your code is broken?You have a getter method that seems to set!? I'm confused.
_dnoyeBa at 2007-7-12 2:38:52 > top of Java-index,Core,Core APIs...
# 2

I know that DCL is broken under certain circumstances (but I have read it may work with modern JVM and the use of volatile variables for example).

So: is it broken with this specific implementation and if so, what should be done to make it work ?

The getter method is potentially setting a value (like in ConcurrentHashMap.putIfAbsent) and it uses a ValueCreator in order to actually create the value only if it is not already present in the map.

franck.wolffa at 2007-7-12 2:38:52 > top of Java-index,Core,Core APIs...
# 3

To have simple and thread safe collection try this way,

Collections.synchronizedMap(Map collection).

Returns a synchronized (thread-safe) map backed by the specified map.

I do not know why you try to implement the lock by yourself, when there are simple ways to do it.

Try to avoid using RuntimeException. The NamingException should be translated into a Application Exception.

bdsaia at 2007-7-12 2:38:52 > top of Java-index,Core,Core APIs...