Может быть немного поздно, но вот мои два цента.
Если вы используете Java 8, вы можете использовать метод computeIfPresent . Если значение для указанного ключа присутствует и не равно нулю, то оно пытается вычислить новое сопоставление, учитывая ключ и его текущее сопоставленное значение.
final Map<String,Integer> map1 = new HashMap<>();
map1.put("A",0);
map1.put("B",0);
map1.computeIfPresent("B",(k,v)->v+1); //[A=0, B=1]
Мы также можем использовать другой метод putIfAbsent для установки ключа. Если указанный ключ еще не связан со значением (или сопоставлен со значением NULL), этот метод связывает его с данным значением и возвращает значение NULL, иначе возвращается текущее значение.
В случае если карта является общей для всех потоков, мы можем использовать ConcurrentHashMapи AtomicInteger . Из документа:
An AtomicIntegerявляется значением int, которое может быть обновлено атомарно. AtomicInteger используется в приложениях, таких как счетчики с атомным приращением, и не может использоваться в качестве замены для Integer. Тем не менее, этот класс расширяет Number, чтобы обеспечить единообразный доступ инструментам и утилитам, которые работают с классами на основе чисел.
Мы можем использовать их как показано:
final Map<String,AtomicInteger> map2 = new ConcurrentHashMap<>();
map2.putIfAbsent("A",new AtomicInteger(0));
map2.putIfAbsent("B",new AtomicInteger(0)); //[A=0, B=0]
map2.get("B").incrementAndGet(); //[A=0, B=1]
Следует обратить внимание на то, что мы вызываем getзначение ключа Bи затем вызываем incrementAndGet()его значение, которое, конечно же, является ключом AtomicInteger. Мы можем оптимизировать его, так как метод putIfAbsentвозвращает значение ключа, если оно уже присутствует:
map2.putIfAbsent("B",new AtomicInteger(0)).incrementAndGet();//[A=0, B=2]
Кроме того, если мы планируем использовать AtomicLong, то в соответствии с документацией в условиях высокой конкуренции ожидаемая пропускная способность LongAdder значительно выше за счет более высокого потребления пространства. Также проверьте этот вопрос .