Увеличить значение в Hashmap потокобезопасным способом, сохраняя высокую производительность без синхронизации?

У меня есть модель, которая имеет разные переменные.

public class Model implements Serializable{

    public final static int STATE_INIT = 0;
    public final static int STATE_READY = 1;

    private Integer state = STATE_INIT;
    private HashMap<Integer,Integer>pageRequests = new HashMap<>();
    private HashMap<Integer,Integer>impr = new HashMap<>();
    private HashMap<Integer,Integer>clicks = new HashMap<>();

    public void incrementPageRequests(int accountId){

   if(this.pageRequests.get(accountId) != null){
       this.pageRequests.put(accountId,this.pageRequests.get(accountId) +1);
   } else {
       this.pageRequests.put(accountId,1);
   }
}

public void incrementImprServed(int accountId){

    if(this.imprServed.get(accountId) != null){
        this.imprServed.put(accountId,this.imprServed.get(accountId) +1);
    } else {
        this.imprServed.put(accountId,1);
    }
}

public void incrementClicksServed(int accountId){

    if(this.clicksServed.get(accountId) != null){
        this.clicksServed.put(accountId,this.clicksServed.get(accountId) +1);
    } else {
        this.clicksServed.put(accountId,1);
    }
}

}

Теперь, когда я запускаю сервер, модель создается, это одноэлементный компонент. я хочу иметь возможность изменять хэш-карту модели, когда кто-то вызывает конечную точку

/ приращение

@GetMapping(path = "/increment")
    public String increment(){
        model.incrementPageRequests(1);
        return "Okay";
    }

В настоящее время этот incrementPageRequest не является потокобезопасным, когда я добавляю synchronized Ключевое слово: метод становится потокобезопасным, но я слышал, что синхронизация очень дорогая, и я ищу высокую пропускную способность и производительность.

Как я могу добиться того же без синхронизации и сохранения высокой производительности?

Обновить

Пробовал с Concurrent HashMap, и все равно не удается, я использую Jmeter для тестирования одновременных вызовов API

Как мне изменить эту логику, чтобы она работала в параллельной хэш-карте

 if(this.pageRequests.get(accountId) != null){
           this.pageRequests.put(accountId,this.pageRequests.get(accountId) +1);
       } else {
           System.out.println("Here");
           this.pageRequests.putIfAbsent(accountId,1);
       }

1 ответ

Сначала: создайте тест, прежде чем решить, какое из решений вам поможет.

Также вы выполняете немного избыточную работу здесь (и в других методах тоже):

if(this.pageRequests.get(accountId) != null){
    this.pageRequests.put(accountId,this.pageRequests.get(accountId) +1);
} else {
    this.pageRequests.put(accountId,1);
}

Вместо

final String value = this.pageRequests.get(accountId);
if(value == null){
    this.pageRequests.put(accountId, 1);
    return;
}
this.pageRequests.put(accountId, value + 1);

Теперь у вас будет 1 доступ для чтения к карте меньше.

Относительно вашего второго вопроса "Как мне изменить эту логику, чтобы она работала в параллельной хэш-карте", измените это:

private HashMap<Integer, Integer> pageRequests = new HashMap<>();

тоже:

private Map<Integer, Integer> pageRequests = new ConcurrentHashMap<>();

Сохранение частного поля в качестве интерфейса позволяет упростить изменение реализации карты.

Другие вопросы по тегам