0

I have an issue on which I need to run .register at most one time on a multi-threaded env, so i tried to use ConcurrentHashMap but seems like its not thread-safe or I'm using it correctly

object NonFunctionalMetrics {

  val histograms = new ConcurrentHashMap[String, Histogram](10).asScala
  def workerProcessingHistogram(name: String): Histogram = {
    val histogramName = s"${prefix}_${name.toSnakeCase}_processing_time"
    histograms.getOrElseUpdate(
                              key = histogramName,
                              op = Histogram.build(histogramName, s"${name} worker processing time in microseconds")
                                .labelNames("status")
                                .linearBuckets(config.service.metrics.http.histogramStart, config.service.metrics.http.histogramWidth, config.service.metrics.http.histogramCount)
                                .register()
    )
  }
}

throws me exception

Collector already registered that provides name: my_app_new_site_exclusion_worker_processing_time_count

on:

    val onSuccessHistogram: Histogram.Child = NonFunctionalMetrics.workerProcessingHistogram(worker.name).labelSuccess()
    val onFailureHistogram: Histogram.Child = NonFunctionalMetrics.workerProcessingHistogram(worker.name).labelFailure()

When I'm adding synchronized its working greats, as follows:

 def workerProcessingHistogram(name: String): Histogram = synchronized {
    val histogramName = s"${prefix}_${name.toSnakeCase}_processing_time"
    histograms.getOrElseUpdate(
                              key = histogramName,
                              op = Histogram.build(histogramName, s"${name} worker processing time in microseconds")
                                .labelNames("status")
                                .linearBuckets(config.service.metrics.http.histogramStart, config.service.metrics.http.histogramWidth, config.service.metrics.http.histogramCount)
                                .register()
    )
  }

I saw that the get(key) two threads are getting false answer and create the histogram with register - doesn't the ConcurrentHashMap need to handle those scenarios?

2
  • Well, this is just a shot into the blue: The access to your ConcurrentHashMap is by definition thread safe, but your workerProcessingHistogram function is not. You first create the name and then access the histogram. So, it's not an atomic operation.
    – Fildor
    Commented May 17, 2022 at 6:25
  • 1
    Haven't been on Java for some time now, but as far as I remeber, the synchronized keyword syncs on the class. So, every call is "serialized" (not happening in parallel). UNfortunately, I am not up to date about possible alternatives, that will perform better for you.
    – Fildor
    Commented May 17, 2022 at 6:28

1 Answer 1

1

You could use computeIfAbsent on the underlying Java ConcurrentHashMap. But getOrElseUpdate on a ConcurrentMap returned by .asScala will use the non-concurrent implementation of mutable Map in Scala.

0

Not the answer you're looking for? Browse other questions tagged or ask your own question.