J'ai une ConcurrentHashMap
et une méthode qui met une chaîne dans la carte, puis je fais quelques actions dans un bloc synchronisé basé sur la valeur insérée.ConcurrentHashMap putIfAbsent première fois
putIfAbsent
renvoie la valeur précédente associée à la clé spécifiée, ou null s'il n'y avait pas de correspondance pour la clé - en fonction de la documentation officielle
Il y a 2 actions qui sont exécutées selon que putIfAbsent
renvoie la valeur null ou pas.
Maintenant, voici l'astuce. Je souhaite que la première action (lorsque putIfAbsent
renvoie null) soit exécutée en premier et que tous les autres threads soient mis en attente. Mon code fonctionne comme prévu dans 95% des cas.
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");
}
}
}
Si j'appelle cette méthode avec la même valeur de chaîne de fils différents login("some_id");
parfois (environ 5% du temps) je reçois ce message sur la console:
Second login
First login
Que dois-je changer être toujours sûr que First login
est exécuté en premier?
Mise à jour: D'après ce que j'ai lu est-il possible que logins.get (id) renvoie null, donc la synchronisation sur un objet nul?
logins.putIfAbsent (id, id), et vos instructions de bloc synchronisées ne sont pas atomiques. C'est pourquoi parfois le deuxième login est exécuté en premier.Aussi, il n'est pas bon de synchroniser sur les littéraux de chaîne –
Est-ce que 'map' devrait être' logins'? –
@MichaelEaster oui. désolé j'ai modifié le code –