ConcurrentHashMap и ReentrantReadWriteLock

У меня есть один поток, который обновляет данные в Map, и несколько потоков, которые читают эти данные. Теперь мой код выглядит так:

public class Updater {
    private ConcurrentMap<String, Integer> valuesMap = new ConcurrentHashMap<>();
    private ReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();

    public void update(Settings settings) {
        reentrantReadWriteLock.writeLock().lock();
        try {
            for (Map.Entry<String, Integer> entry : valuesMap.entrySet()) {
                valuesMap.put(entry.getKey(), 
                              entry.getValue() + settings.getUpdateValue());
            }
        } finally {
            reentrantReadWriteLock.writeLock().unlock();
        }
    }

    public Integer getValue(String key) {
        reentrantReadWriteLock.readLock().lock();
        try {
            return valuesMap.get(key);
        } finally {
            reentrantReadWriteLock.readLock().unlock();
        }
    }
}

Но я думаю, что перестарался. Могу ли я использовать только ConcurrentHashMap в этой ситуации?


person Violetta    schedule 15.06.2020    source источник
comment
Я на 90% уверен, что ConcurrentHashMap будет достаточно. Единственное, что я хотел бы изменить, это использовать ConcurrentHashMap.compute() для обновления вместо комбинации getValue() + put() - даже если это не будет иметь большого значения в случае обновления одного потока.   -  person Amongalen    schedule 15.06.2020


Ответы (1)


Могу ли я использовать только ConcurrentHashMap в этой ситуации?

Это зависит от того, хотите ли вы, чтобы операция update была атомарной; то есть хотите ли вы, чтобы читатель никогда не видел состояние карты, когда были выполнены только некоторые из put операций.

  • Если update не обязательно должно быть атомарным, то блокировка не нужна. Фактически if является нежелательным узким местом параллелизма.

  • Если update должен быть атомарным, то необходима блокировка. Но если вы контролируете доступ с помощью замков, вам не нужно использовать ConcurrentHashMap. Простой HashMap был бы лучше.

Я не думаю, что у ConcurrentHashMap есть способ реализовать несколько операций put как атомарное действие.

person Stephen C    schedule 15.06.2020
comment
Верно, невозможно выполнить атомарные обновления нескольких ключей с помощью ConcurrentHashMap, и любое использование дополнительного механизма блокировки сводит на нет всю цель ConcurrentHashMap. Когда атомарность для нескольких ключей не требуется, исходный код OP все равно должен исправить обновление одного ключа, то есть путем замены valuesMap.put(entry.getKey(), entry.getValue()+settings.getUpdateValue()); на valuesMap.merge(entry.getKey(), settings.getUpdateValue(), Integer::sum);. Предполагая, что settings.getUpdateValue() не подлежит одновременным обновлениям, тогда блокировку можно снять. - person Holger; 17.06.2020