2

У меня есть ConcurrentHashMapподписок, которые содержат другой объект (sessionCollection), и мне нужно сделать следующую итерационную операцию:Как сделать атомарную итеративную операцию на ConcurrentHashMaps?

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

где sessionCollection.removeAllSubscriptionsOfSession делает другую итерационную операцию над коллекцией (также ConcurrentHashMap) внутри 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*()), но они не являются атомарными относительно всей карты. Единственный способ сделать изменения на атомной партии на карте - реализовать всю необходимую синхронизацию самостоятельно. Например, с помощью блоков 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, поэтому никто не может их модифицировать без надлежащей синхронизации.

+0

Вы также можете использовать Collections.synchronizedMap и синхронизировать на самой карте, так как synchronizedMap поддерживает блокировку на стороне клиента. Однако производительность будет намного хуже, чем ConcurrentHashMap. Вам нужно решить, действительно ли важно, чтобы вся карта была заблокирована, действительно важна для вашей логики, если тогда нет выбора, кроме как заблокировать всю карту. Во многих случаях такая блокировка не нужна. –

+0

Согласен, 'SynchronizedMap.forEach()' может использоваться для выполнения синхронизированных пакетных обновлений. Технически это будет тот же самый обертку, как я описал, но без семантики операций. –

 Смежные вопросы

  • Нет связанных вопросов^_^