2

は私が持っている他のオブジェクト(sessionCollection)が含まれていて、私は次の反復操作を行う必要がありConcurrentHashMapサブスクリプション:sessionCollection.removeAllSubscriptionsOfSession内部(もConcurrentHashMap)のコレクションを介して別の反復操作を行いConcurrentHashMapsでアトミックネストされた反復操作を行う方法は?

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

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

この全体的な手順はオミック操作?

答えて

1

ConcurrentHashMapはバッチ処理(forEach*())を持っていますが、マップ全体に対してアトミックではありません。地図上で一括変更を行う唯一の方法は、必要な同期をすべて自分で実装することです。たとえば、​​ブロックを明示的に使用するか、必要に応じて同期処理を行うマップのラッパー(または拡張子)を作成します。とにかく同期を行う必要があるので、この場合は、単純な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外に漏れるのトピック・ツー・セッションマップ(少なくともその修正版)を保護したいと思います、誰も適切な同期なしでそれらを変更することはできません。

+0

synchronizedMapはクライアント側のロックをサポートしているので、Collections.synchronizedMapを使用してマップ自体で同期することもできます。パフォーマンスはConcurrentHashMapよりもはるかに悪くなります。マップ全体がロックされていることを確認するかどうかは、ロジックにとって実際に重要かどうかを判断する必要があります。そうしないと、マップ全体をロックする以外に選択肢がありません。多くの場合、この種のロックは不要です。 –

+0

私は同意します、 'SynchronizedMap.forEach()'は同期バッチ更新を実行するのに使用できます。技術的には、私が記述したものと同じラッパーになりますが、操作の意味はありません。 –

関連する問題