programmation Java (école d'ingénieur) · Chapitre 15 · Application directe du cours
Virements croisés
Threads · niveau 3 (difficile)
Énoncé
On programme ainsi un virement entre deux comptes :
static void virer(Compte de, Compte vers, int montant) {
synchronized (de) {
synchronized (vers) {
de.solde -= montant;
vers.solde += montant;
}
}
}
Un fil fait cent mille virements d'un euro de a vers b, un autre cent mille de b vers a.
- Pourquoi faut-il deux verrous ?
- Le programme se bloque. Expliquer pourquoi, sur un entrelacement.
- Corriger
vireren donnant à chaque compte un numéro unique, et vérifier que le total des deux comptes est conservé.
Corrigé
- Le virement modifie deux comptes ; il doit être indivisible pour les deux, sinon un autre fil pourrait voir l'argent « en vol » (débité d'un compte, pas encore crédité sur l'autre), ou modifier l'un des comptes au même moment.
- Le fil 1 exécute
virer(a, b, 1)et prend le verrou dea; au même moment, le fil 2 exécutevirer(b, a, 1)et prend celui deb. Le fil 1 attend alorsb, détenu par le fil 2, qui attenda, détenu par le fil 1 : c'est un interblocage. Sur la machine de l'auteur, il survient à chaque exécution, en une fraction de seconde. - On prend toujours le verrou du compte de plus petit numéro en premier, quel que soit le sens du virement :
static void virer(Compte de, Compte vers, int montant) {
Compte premier = de.numero < vers.numero ? de : vers;
Compte second = premier == de ? vers : de;
synchronized (premier) {
synchronized (second) {
de.solde -= montant;
vers.solde += montant;
}
}
}
a = 10000, b = 10000, total = 20000
Le cycle d'attente est impossible : un fil qui détient le second verrou détient forcément déjà le premier.
100 % gratuit
La suite du chapitre est sur Adloun
- 9 autres exercices corrigés dans ce chapitre
- Les 2 QCM du chapitre, le premier sans compte
- Le tuteur, qui guide pas à pas sans donner la réponse
Sans compte : le cours et le premier QCM. Exercices et tuteur : inscription gratuite en 30 secondes, sans carte bancaire.