Reputation: 2332
I am developing a metrics store (Map) , which basically collects metrics about some operations such as
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);
}
}
}
Upvotes: 1
Views: 338
Reputation: 29710
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);
}
Upvotes: 3