Volatile для использования с Concurrent Collection? - PullRequest
1 голос
/ 11 октября 2019

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

  • mix
  • max
  • counter
  • timeElapsed [] и т. Д.

Здесь ключ - это имя метода, а значения - это метрики.

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);
        }
    }

}

1 Ответ

3 голосов
/ 11 октября 2019

Нужно ли сделать хранилище переменных 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);
}
...