I had a requirement, when I had to have Map<Comparable, Set<Comparable>> , where the insert on the map would be parallel, as well as in the corresponding set, but after the key was used up from the map, it had to be removed, think, Work done every two seconds that consumes the whole Set<Comparable> from a specific key, but the insert must be completely parallel so that most of the values โโare buffered when the task starts, here is my implementation:
Note. . I use Guava Maps helper classes to create parallel Maps. In addition, this solution emulates the Java concurrency in Practical Listing 5.19 :
import com.google.common.collect.MapMaker; import com.google.common.collect.Sets; import java.util.Collection; import java.util.Set; import java.util.concurrent.ConcurrentMap; public class ConcurrentMultiMap<K extends Comparable, V extends Comparable> { private final int size; private final ConcurrentMap<K, Set<V>> cache; private final ConcurrentMap<K, Object> locks; public ConcurrentMultiMap() { this(32, 2); } public ConcurrentMultiMap(final int concurrencyLevel) { this(concurrencyLevel, 2); } public ConcurrentMultiMap(final int concurrencyLevel, final int factor) { size=concurrencyLevel * factor; cache=new MapMaker().concurrencyLevel(concurrencyLevel).initialCapacity(concurrencyLevel).makeMap(); locks=new MapMaker().concurrencyLevel(concurrencyLevel).initialCapacity(concurrencyLevel).weakKeys().weakValues().makeMap(); } private Object getLock(final K key){ final Object object=new Object(); Object lock=locks.putIfAbsent(key, object); if(lock == null){ lock=object; } return lock; } public void put(final K key, final V value) { synchronized(getLock(key)){ Set<V> set=cache.get(key); if(set == null){ set=Sets.newHashSetWithExpectedSize(size); cache.put(key, set); } set.add(value); } } public void putAll(final K key, final Collection<V> values) { synchronized(getLock(key)){ Set<V> set=cache.get(key); if(set == null){ set=Sets.newHashSetWithExpectedSize(size); cache.put(key, set); } set.addAll(values); } } public Set<V> remove(final K key) { synchronized(getLock(key)){ return cache.remove(key); } } public Set<K> getKeySet() { return cache.keySet(); } public int size() { return cache.size(); } }
Guido Medina Sep 12 '12 at 10:11 2012-09-12 10:11
source share