I have a requirement to have key value pairs, where the value can be a set. This data structure should be thread safe to add remove elements to the set in a multi threaded environment.
My requirement is to create a subscription list, here people can subscribe for different topics. This subscription list should be concurrent, thread safe and fast. I was thinking about Using ConcurentHashMap and ConcurrentHashSet, this will not help me since, I have to put the syncronization block at the top level and it will block the entire map until the put/remove operation completes.
-
Not in the JRE. Maybe in Apache Commons etc.user207421– user2074212017年10月27日 05:24:38 +00:00Commented Oct 27, 2017 at 5:24
-
I have checked in Apache Comments I could not find one. There are multi valued hash maps but they are not thread safe.Rasekaran– Rasekaran2017年10月27日 05:30:45 +00:00Commented Oct 27, 2017 at 5:30
-
ConcurrentHashMap can be used, with value as SET . Any observation?Vipin CP– Vipin CP2017年10月27日 05:46:10 +00:00Commented Oct 27, 2017 at 5:46
-
Can't you use simple synchronization? Does it have to be a concurrent structure?shmosel– shmosel2017年10月27日 06:09:59 +00:00Commented Oct 27, 2017 at 6:09
-
@shmosel If I use synchronization in top level It will block entire map, then there is no concurrency.Rasekaran– Rasekaran2017年10月27日 09:35:36 +00:00Commented Oct 27, 2017 at 9:35
2 Answers 2
There is no pre-rolled solution, but it is possible to achieve thread-safe concurrency for simple values using a ConcurrentMap<K, Set<V>>
which has Set<V>
values made from ConcurrentMap<V, Boolean>
using Collections.newSetFromMap(Map<V,Boolean>)
.
Then, to get each value set in an atomic way, use ConcurrentMap.computeIfAbsent(K, Function<? super K, ? extends Set<V>>)
:
ConcurrentMap<String, Set<Integer>> multimap = new ConcurrentHashMap<>();
Set<Integer> fooValues = multimap.computeIfAbsent("foo", key -> Collections.newSetFromMap(new ConcurrentHashMap<Integer, Boolean>()));
If you want your values to have a stable iteration order, you can use a ConcurrentSkipListSet
to hold values instead:
ConcurrentMap<String, NavigableSet<Integer>> multimap = new ConcurrentHashMap<>();
NavigableSet<Integer> fooValues = multimap.computeIfAbsent("foo", key -> new ConcurrentSkipListSet<>());
Likewise, in order to remove Set<V>
value holder instances in a thread-safe fashion, you can use ConcurrentMap.computeIfPresent(K, BiFunction<? super K,? super Set<V>,? extends Set<V>>)
:
public static <K, V> void remove(final ConcurrentMap<K, Collection<? extends V>> multimap, final K key,
final V value) {
multimap.computeIfPresent(key, (k, oldValues) -> {
final Collection<? extends V> newValues;
if (oldValues.remove(value) && oldValues.isEmpty()) {
// Remove the empty set from the multimap
newValues = null;
} else {
newValues = oldValues;
}
return newValues;
});
}
Note that there is no "ConcurrentHashSet
" class provided by the Java core libraries.
1 Comment
you write "the value can be a set", but don't mention what the key is. In any case, Hashtable, the first map that was present in Java, is thread safe wrt adding/removing/replacing key,value pairs.
You can create a thread-safe Set with one of the methods described here. Whether that set is stored as value in an hashmap makes no difference.
5 Comments
Explore related questions
See similar questions with these tags.