Reputation: 9421
I have a ConcurrentHashMap
subscriptions that contain another object (sessionCollection) and I need to do the following iterative operation:
subscriptions.values().forEach(sessionCollection ->
sessionCollection.removeAllSubscriptionsOfSession(sessionId));
where sessionCollection.removeAllSubscriptionsOfSession
does another iterative operation over a collection (also ConcurrentHashMap
) inside sessionCollection:
// inside SessionCollection:
private final ConcurrentHashMap<String, CopyOnWriteArrayList<String>> topicsToSessions =
new ConcurrentHashMap<>();
public void removeAllSubscriptionsOfSession(String sessionId) {
// Remove sessions from all topics on record
topicsToSessions.keySet().forEach(topicSessionKey ->
removeTopicFromSession(sessionId, topicSessionKey));
}
What would be the steps to make this overall atomic operation?
Upvotes: 2
Views: 182
Reputation: 6197
ConcurrentHashMap
has batch operations (forEach*()
), but they are not atomic with respect to the whole map. The only way to make atomic batch changes on a map is to implement all the necessary synchronization yourself. For instance, by using synchronized
blocks explicitly or by creating a wrapper (or an extension) for your map that will take care of synchronization where needed. In this case a simple HashMap
will suffice since you have to do synchronization anyway:
public class SubscriptionsRegistry {
private final Map<Integer, SessionCollection> map = new HashMap<>();
public synchronized void removeSubscriptions(Integer sessionId) {
map.values().forEach(...);
}
public synchronized void addSubscription(...) {
...
}
...
}
You'll also want to protect the topics-to-sessions maps (at least their modifiable versions) from leaking outside your SubscriptionsRegistry
, so nobody is able to modify them without proper synchronization.
Upvotes: 1