ObsceneAlbatros
ObsceneAlbatros

Reputation: 21

How to utilize ConcurrentHashMap.merge() with a shared AtomicInteger

I have a shared global counter that I want to check is less than a total before doing a concurrent computation and update into a map. How can I use modern java concurrency utils / API to ensure this is atomic?


class SharedAccess {

    AtomicInteger globalCounter = new AtomicInterger();
    Map<String, Integer> counterPerKey = new ConcurrentHashMap<>()

    class Holder{
        Integer value
    }

    public Holder incrementForKeyMultipleThreads(String key) {
         if (total.get() < 1000) {

          Integer newTotal = counterPerKey.merge(key, 1, Integer::sum);
          globalCounter.increment();
         return new Holder(newTotal);

    }

  }

}

EDIT: This is solved by the merge function actually being atomic too. Therefore you get the benefit of the multiple thread access to the rest of the map, and the atomic inc on the total counter.


class SharedAccess {

    AtomicInteger globalCounter = new AtomicInterger();
    Map<String, Integer> counterPerKey = new ConcurrentHashMap<>()

    class Holder{
        Integer value
    }

    public Holder incrementForKeyMultipleThreads(String key) {
         if (total.get() < 1000) {

          Integer newTotal = counterPerKey.merge(key, 1, (v1, v2) -> {
              globalCounter.increment();
              return v1+v1;
          }  

         return new Holder(newTotal);

    }

  }

}

Upvotes: 0

Views: 331

Answers (1)

Kartik
Kartik

Reputation: 7917

Modern java still uses the same basic principles of thread-safety. You have a check-then-act scenario, which covers pretty much the whole method. So you can make the method synchronized:

public synchronized Holder incrementForKeyMultipleThreads(String key) {
    if (globalCounter.get() < 1000) {
        globalCounter.increment();
        return new Holder(counterPerKey.merge(key, 1, Integer::sum));
    }
    return null;
}

And then if this is the only place you are using (reading or writing) globalCounter, you can change it to int.

Upvotes: 1

Related Questions