1

I am developing a metrics store (Map) , which basically collects metrics about some operations such as

  • mix
  • max
  • counter
  • timeElapsed[] etc

Here Key is the name of the method and value are metrics about it.

Spring can help me create singleton object of MetricStore, i am using ConcurrentHashMap to avoid race condition when multiple REST request comes in parallel.

My query 1- Do i need to make MetricStore variable store volatile? to improve the visibility among multiple requests. 2- I am using Map as the base class and ConcurrentHashMap as Implemetnation, does it affect as Map is not 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);
        }
    }

}
Digital Alchemist
  • 2,324
  • 1
  • 15
  • 17
  • 2
    re: _"Map is not ThreadSafe"_ – [java.util.Map](https://docs.oracle.com/javase/8/docs/api/java/util/Map.html) isn't threadsafe or non-threadsafe, it's just an interface to some underlying implementation. – Kaan Oct 11 '19 at 16:40
  • Thanks @kaan for the comment – Digital Alchemist Oct 11 '19 at 16:54

1 Answers1

3

Do i need to make MetricStore variable store volatile?

No, because you are not changing the value of store (i.e. store can be marked as final and the code should still compile).

I am using Map as the base class and ConcurrentHashMap as Implemetnation, does it affect as Map is not ThreadSafe

Because you're using a ConcurrentHashMap as the implementation of Map, it is thread-safe. If you want the declared type to be more specific, Map can be changed to ConcurrentMap.


The bigger issue here is that you're using containsKey before calling put and remove when you should be using compute and computeIfPresent, which are atomic operations:

@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);
}
Jacob G.
  • 28,856
  • 5
  • 62
  • 116
  • Thanks so much for enlightening me. Just out of curiosity and for learning. Is compute doing the same job as if i have used synchronized block? – Digital Alchemist Oct 11 '19 at 16:53
  • 1
    @DigitalAlchemist It's a bit more complicated than that. See: [ConcurrentHashMap computeIfAbsent](https://stackoverflow.com/a/26483476/7294647) – Jacob G. Oct 11 '19 at 16:56