Увеличить значение в 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<>();
Сохранение частного поля в качестве интерфейса позволяет упростить изменение реализации карты.