ConcurrentHashMap и операции, которые охватывают 2 отдельных вызова - PullRequest
1 голос
/ 07 мая 2019

Я понимаю, что методы ConcurrentHashMap являются потокобезопасными, но как насчет составных операций, которые не являются атомарными, например, посмотрите этот фрагмент кода - если 2 разных потока вызывают его одновременно с одним и тем же «myKey», это невозможноможет возникнуть условие гонки?

myMap - это ConcurrentHashMap

myValues = myMap.get(myKey);
if (myValues == null) {
    myValues = new List()
    myMap.add(myKey, myValues);
}
myValue.add(new list item);

Как записать вышеописанное в безопасном для потока виде с помощью только ConcurrentHashMap и без использования отдельных блокировок и т. д.,

putIfAbsent, похоже, тоже не решил проблему или что-то вроде этого возможно:

myValues =  myMap.putIfAbsent(myKey, new List());
myValues.add(new list item);

Это правильно и безопасно для потока?
Спасибо

1 Ответ

2 голосов
/ 07 мая 2019

Использовать computeIfAbsent , который является атомарным:

Документация:

Если указанный ключ еще не связан со значением, попытается вычислить его значение с помощьюданная функция отображения и вводит ее в эту карту, если не null.Весь вызов метода выполняется атомарно, поэтому функция применяется не более одного раза для каждой клавиши.Некоторые попытки обновления этой карты другими потоками могут быть заблокированы во время вычислений, поэтому вычисления должны быть короткими и простыми и не должны пытаться обновить какие-либо другие сопоставления этой карты.

Простое использование:

ConcurrentHashMap<String, List<String>> map = new ConcurrentHashMap<>();
List<String> list = map.computeIfAbsent("myKey", key -> new CopyOnWriteArrayList<>());

Редактировать
Как правильно заметил @Holger, ArrayList в этом случае небезопасно для использования.Намного безопаснее использовать CopyOnWriteArrayList , который является потокобезопасным вариантом ArrayList.

...