J'ai un objet Utilisateur avec deux verrous, inventoryLock et currencyLock. Souvent, ces verrous seront utilisés individuellement, par ex.Comment éviter une impasse facile?
synchronized (user.inventoryLock) {
// swap items
tmp = user.inventory[x];
user.inventory[x] = user.inventory[y];
user.inventory[y] = tmp;
}
ou
synchronized (user.currencyLock) {
if (user.money < loss) throw new Exception();
user.money -= loss;
}
Mais parfois, un morceau de code nécessite les deux serrures:
synchronized (user.currencyLock) {
synchronized (user.inventoryLock) {
if (user.money < item.price) throw new Exception();
user.money -= item.price;
user.inventory[empty] = item;
}
}
Cela semble simple, mais il y a plus de bits de code en utilisant les deux verrous que juste cet exemple, et je sais par expérience que si plusieurs morceaux de code requièrent les mêmes verrous partagés, ils risquent d'être bloqués.
Quel est un bon moyen d'éviter cela?
Est-ce qu'il y a peut-être un mécanisme qui me permet de verrouiller atomiquement deux objets?
Votre code montre un sérieux manque d'encapsulation. Vous accédez directement à l'état de l'utilisateur, sans passer par les méthodes. L'état doit être encapsulé dans la classe, ce qui devrait centraliser la synchronisation et s'assurer que toute la synchronisation nécessaire est faite. Vous forcez chaque client de votre utilisateur à se synchroniser correctement, plutôt que de fournir ce service dans la classe User elle-même. –
@JBNizet Ceci est juste un exemple de code. Le code réel implique, entre autres, des appels de base de données que la classe d'utilisateurs n'est pas capable d'effectuer. –