如何在ConcurrentHashMaps上使原子成为嵌套迭代操作?

时间:2016-09-15 09:31:29

标签: java multithreading concurrency thread-safety java.util.concurrent

我有ConcurrentHashMap 订阅,其中包含另一个对象( sessionCollection ),我需要执行以下迭代操作:

  subscriptions.values().forEach(sessionCollection -> 
     sessionCollection.removeAllSubscriptionsOfSession(sessionId));

其中sessionCollection.removeAllSubscriptionsOfSession sessionCollection 内的集合(也是ConcurrentHashMap)执行另一次迭代操作:

// 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));
}

进行这种整体原子操作的步骤是什么?

1 个答案:

答案 0 :(得分:1)

ConcurrentHashMap具有批处理操作(forEach*()),但它们与整个地图不是原子的。在地图上进行原子批量更改的唯一方法是自己实现所有必要的同步。例如,通过显式使用synchronized块或通过为地图创建包装器(或扩展)来处理需要的同步。在这种情况下,简单的HashMap就足够了,因为你必须进行同步:

public class SubscriptionsRegistry {
    private final Map<Integer, SessionCollection> map = new HashMap<>();

    public synchronized void removeSubscriptions(Integer sessionId) {
        map.values().forEach(...);
    }

    public synchronized void addSubscription(...) {
        ...
    }

    ...
}

您还希望保护主题到会话的地图(至少是其可修改的版本)不会泄漏到SubscriptionsRegistry之外,因此没有人能够在没有正确同步的情况下修改它们。