I have a ConcurrentHashMap and a method that puts a String in the map, then I do some actions in a synchronized block based on the inserted value.
putIfAbsent returns the previous value associated with the specified key, or null if there was no mapping for the key - based on the official documentation
There are 2 actions that are executed based on whether putIfAbsent returns null or not.
Now here is the trick. I want the first action (when putIfAbsent returns null) to be executed first and all other threads to be put on hold.
My code works as intended 95% of the time.
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");
}
}
}
If I call this method with the same String value from different threads login("some_id"); sometimes (around 5% of the time) I get this message on console:
Second login
First login
What do I need to change to always be sure that First login is executed first?
Update: From what I read is it possible that logins.get(id) return null , therefore synchronizing on a null object?
Note: Also make sure that you remove the entries from hashmaps when the id is deleted
or Use some other field(apart from string id) to synchronize the code