У меня есть ConcurrentHashMap
и метод, который помещает String в карту, тогда я делаю некоторые действия в синхронизированном блоке на основе вставленного значения.ConcurrentHashMap putIfAbsent первый раз
putIfAbsent
возвращает предыдущее значение, связанное с указанным ключом, или нулевое значение, если не было никакого отображения для ключа - на основе официальной документации
Есть 2 действия, которые выполняются на основе того, обнулить putIfAbsent
возвращается или нет.
Теперь вот трюк. Я хочу первое действие (когда putIfAbsent
возвращает null), который будет выполнен первым, и все остальные потоки будут переведены на удержание. Мой код работает как предполагается 95% времени.
private final ConcurrentHashMap<String, String> logins = new ConcurrentHashMap<>();
public void login(String id){
String inserted=logins.putIfAbsent(id,id);
synchronized(logins.get(id)){
if(inserted==null){
System.out.println("First login");
}else{
System.out.println("Second login");
}
}
}
Если я называю этот метод с тем же значением строки из разных потоков login("some_id");
иногда (около 5% времени) я получаю это сообщение на консоль:
Second login
First login
Что мне нужно изменить всегда быть уверенным, что сначала выполняется First login
?
Обновление: Из чего я прочитал, возможно, что logins.get (id) возвращает null, поэтому синхронизация на нулевом объекте?
logins.putIfAbsent (id, id), а ваши операторы с синхронизированным блоком не являются атомарными. Поэтому иногда второй вход выполняется первым.Также не рекомендуется синхронизировать строковые литералы –
Должно ли 'map' быть' logins'? –
@MichaelEaster да. извините, я изменил код –