Adloun

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 virer en 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 de a ; au même moment, le fil 2 exécute virer(b, a, 1) et prend celui de b. Le fil 1 attend alors b, détenu par le fil 2, qui attend a, 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

Exercice suivant et tuteur

Sans compte : le cours et le premier QCM. Exercices et tuteur : inscription gratuite en 30 secondes, sans carte bancaire.

Le cours du chapitre · Tous les exercices du chapitre

Exercice suivant et tuteur →