Является ли изменение значения Map атомарной операцией? - PullRequest
8 голосов
/ 12 марта 2012

Мне было интересно, нужна ли синхронизация или использование параллельного класса, или, наоборот, является ли потокобезопасным использование не параллельного класса и не выполняется синхронизация на карте в многопоточной среде, если меняется только модификация картызначения карты.

Причина, по которой я спрашиваю это, заключается в том, что HashMap (и другая документация по непараллельным картам) имеют этот комментарий:

Обратите внимание, что эта реализация не синхронизирована.Если несколько потоков обращаются к хэш-карте одновременно, и хотя бы один из потоков структурно изменяет карту, она должна быть синхронизирована извне.(Структурная модификация - это любая операция, которая добавляет или удаляет одно или несколько сопоставлений; простое изменение значения, связанного с ключом, который уже содержится в экземпляре, не является структурной модификацией.) Обычно это выполняется путем синхронизации с некоторым объектом, который естественным образом инкапсулирует карту.

Что заставляет меня поверить, если модификация не является структурной (т. Е. Нет добавленных или удаленных), я смогу обновить (не одновременную) карту без синхронизации.

Я читаю это правильно?Т.е. является ли обновление значения в карте атомарным процессом?

Ответы [ 3 ]

5 голосов
/ 12 марта 2012

Обновление значения карты не является атомарным процессом. Однако наличие нескольких разных потоков, пытающихся одновременно изменять значения карты, не приведет к очень странным исключениям или ошибкам из-за ошибок параллелизма. Например, вы не будете вызывать исчезновение одной из пар ключ / значение или удалять случайные элементы с карты.

Однако обновления, сделанные одним потоком при обновлении пары ключ / значение, не обязательно будут видны другим потокам, если не происходит какая-либо другая синхронизация (например, если значения являются вещами типа AtomicIntegers). Кроме того, нет никакой гарантии, что поток даже увидит свои собственные обновления, поскольку они могут быть засорены каким-либо другим потоком.

Надеюсь, это поможет!

2 голосов
/ 09 марта 2017

Реализации карты, такие как HashMap, TreeMap и т. Д., Не являются ни атомарными, ни поточно-ориентированными, когда дело доходит до обновлений, но вы можете достичь атомарных операций обновления, когда используете ConcurrentHashMap начиная с Java 1.8.

Следующий метод, например, добавит значение для определенного ключа или установит значение, если для ключа не было доступно предыдущее значение.

ConcurrentMap<String, Integer> map = new ConcurrentHashMap<>();

int addValue(String key, int value) {
    return map.compute(key, (k, v) -> v == null ? value : v + value);
}
2 голосов
/ 12 марта 2012

Помещение чего-либо в HashMap не является атомарной операцией:

public V put(K key, V value) {
    if (key == null)
        return putForNullKey(value);
    int hash = hash(key.hashCode());
    int i = indexFor(hash, table.length);
    for (Entry<K,V> e = table[i]; e != null; e = e.next) {
        Object k;
        if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
            V oldValue = e.value;
            e.value = value;
            e.recordAccess(this);
            return oldValue;
        }
    }

    modCount++;
    addEntry(hash, key, value, i);
    return null;
}

Возможно, стоит обернуть HashMap Collections#synchronizedMap.

...