I need to make the following class thread-safe:
//Shared among all threads
public class SharedCache {
private Map<Object, Future<Collection<Integer>>> chachedFutures;
{
chachedFutures = new ConcurrentHashMap<>(); //not sure about that
}
public Future<Collection<Integer>> ensureFuture(Object value,
FutureFactory<Collection<Integer>> ff){
if(chachedFutures.containsKey(value))
return chachedFutures.get(value);
Future<Collection<Integer>> ftr = ff.create();
chachedFutures.put(value, ftr);
return ftr;
}
public Future<Collection<Integer>> remove(Object value){
return chachedFutures.remove(value);
}
}
After reading the article about the ConcurrentHashMap class it's still difficult for me to make a right decision.
Firstly, I tended to make the methods ensureFuture
and remove
just synchronized
. And it would work, but from the performance standpoint it was not very good because of mutually-exclusing.
I don't know the exact (even approximately) amount of threads having access to the Cache
simultaneously and the size of the Cache. Taking into account that
resizing this or any other kind of hash table is a relatively slow operation
I didn't specify the initial size of the map. Also the concurrencyLevel parameter. Is it justified to use ConcurrentHashMap
here or synchronized methods would be enough?
You have following methods:
public Future<Collection<Integer>> ensureFuture(Object value,
FutureFactory<Collection<Integer>> ff){
if(chachedFutures.containsKey(value))
return chachedFutures.get(value);
Future<Collection<Integer>> ftr = ff.create();
chachedFutures.put(value, ftr);
return ftr;
}
public Future<Collection<Integer>> remove(Object value){
return chachedFutures.remove(value);
}
There are some points to be noticed:
ensureFuture
is not synchronized in that case it is possible that one thread invokes containsKey
which returns true
but before next line is executed another thread may remove the entry respective to that key. This can lead to race condition as it is check-then-act
scenario. Check this as well.chachedFutures.put(value, ftr)
but IMO you should use chachedFutures.putIfAbsent(value, ftr)
. For this method if the specified key is not already associated with a value (or is mapped to null) associates it with the given value and returns null, else returns the current value
. Using this you can also avoid contains check.Is it justified to use ConcurrentHashMap here or synchronized methods would be enough?
It depends as CHM needs more memory compared to HashMap due to lot of bookkeeping activities etc. Another alternative is to use Collections.synchronizedMap
which will provide synchronization on a regular HashMap
.
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments