Volatile для использования с Concurrent Collection?

Я разрабатываю хранилище метрик (Map), которое в основном собирает метрики о некоторых операциях, таких как

  • смешивание
  • Максимум
  • прилавок
  • время истекло [] и т. д.

Здесь Key — это имя метода, а value — его метрики.

Spring может помочь мне создать одноэлементный объект MetricStore, я использую ConcurrentHashMap, чтобы избежать состояния гонки, когда несколько запросов REST поступают параллельно.

Мой вопрос 1. Нужно ли мне сделать хранилище переменных MetricStore изменчивым? для улучшения видимости среди нескольких запросов. 2- Я использую Map в качестве базового класса и ConcurrentHashMap в качестве Implemetnation, влияет ли это на то, что Map не является ThreadSafe. -

@Component
class MetricStore{
    public Map<String, Metric> store = new ConcurrentHashMap<>();
    //OR  public volatile Map<String, Metric> store = new ConcurrentHashMap<>();
}

@RestController
class MetricController{
    @Autowired
    private MetricStore metricStore;

    @PostMapping(name="put")
    public void putData(String key, Metric metricData) {
        if(metricStore.store.containsKey(key)) {
            // udpate data
        }
        else {
            metricStore.store.put(key, metricData);
        }
    }

    @PostMapping(name="remove")
    public void removeData(String key) {
        if(metricStore.store.containsKey(key)) {
            metricStore.store.remove(key);
        }
    }

}

person Digital Alchemist    schedule 11.10.2019    source источник
comment
Re: Map не является ThreadSafejava.util.Map не является потокобезопасным или не потокобезопасным, это просто интерфейс для некоторой базовой реализации.   -  person kaan    schedule 11.10.2019
comment
Спасибо @kaan за комментарий   -  person Digital Alchemist    schedule 11.10.2019


Ответы (1)


Нужно ли делать хранилище переменных MetricStore изменчивым?

Нет, потому что вы не меняете значение store (т. е. store можно пометить как final, и код все равно должен компилироваться).

Я использую Map в качестве базового класса и ConcurrentHashMap в качестве Implemetnation, влияет ли это на то, что Map не является ThreadSafe

Поскольку вы используете ConcurrentHashMap в качестве реализации Map, он является потокобезопасным. Если вы хотите, чтобы объявленный тип был более конкретным, Map можно изменить на ConcurrentMap.


Более серьезная проблема заключается в том, что вы используете containsKey перед вызовом put и remove, когда вы должны использовать compute и computeIfPresent, которые являются атомарными операциями:

@PostMapping(name="put")
public void putData(String key, Metric metricData) {
    metricStore.store.compute(key, (k, v) -> {
        if (v == null) {
            return metricData;
        }

        // update data
    });
}

@PostMapping(name="remove")
public void removeData(String key) {
    metricStore.store.computeIfPresent(key, (k, v) -> null);
}
person Jacob G.    schedule 11.10.2019
comment
Большое спасибо, что просветили меня. Просто из любопытства и для обучения. Выполняет ли вычисление ту же работу, как если бы я использовал синхронизированный блок? - person Digital Alchemist; 11.10.2019
comment
@DigitalAlchemist Это немного сложнее. См.: ConcurrentHashMap calculateIfAbsent. - person Jacob G.; 11.10.2019