1. t0 va se suspendre (wait) , puis t1 va afficher un retour à la ligne et réveiller t0.

  2. Le programme affiche 10 lignes « AB » ou « BA » et termine normalement puisque tous les threads terminent.

  3. Si A meurt inopinément avant son dixième rendez-vous, B est bloqué, et le programme ne termine pas normalement.

  4. On peut grouper par paires les appels à sync. Soit donc nAB le nombre de rendez-vous entre A et B, etc.

  5. Et voilà.
    class Barrier {
      
    private int nall, nwait ;

      
    Barrier (int nall) {
        
    this.nall = nall ; nwait = 0 ;
      }

      
    synchronized void sync() {
        nwait++ ;
        
    if (nwait < nall) {
          
    try {
              wait() ;
            } 
    catch (InterruptedException e) {
              System.exit(2) ;
            }
        } 
    else {
          System.out.println() ;
          nwait = 0 ;
          notifyAll() ;
        }
      }

    }
    On remarquera surtout le remplacement d'un booléen par deux entiers et le changement de notify en notifyAll.

    Il faut un moment pour se convaincre du fonctionnement.

  6. Voici la nouvelle barrière.
    class Barrier {
      
    private int nall, nwait ;

      
    Barrier() { nall = nwait = 0 ; }

      
    synchronized void register() {
        nall++ ;
      }

      
    synchronized void checkout() {
        nall-- ;
        
    if (nwait == nall && nwait != 0) {
          System.out.println() ;
          nwait = 0 ;
          notifyAll() ;
        }
      }

      
    synchronized void sync() {
        nwait++ ;
        
    if (nwait < nall) {
          
    try {
              wait() ;
            } 
    catch (InterruptedException e) {
              System.exit(2) ;
            }
        } 
    else {
          System.out.println() ;
          nwait = 0 ;
          notifyAll() ;
        }
      }

    }
    On remarque le changement de constructeur et qu'un renoncement peut entraîner un réveil.

  7. Le changement porte sur d'une part sur la méthode run qui commence par un enregistrement et se termine par un renoncement; et d'autre part sur la construction de la barrière qui ne dépend plus du paramètre n.
    class All extends Thread {
      
    static Barrier rdv = new Barrier() ;
      
    char id ;

      
    All(char id) { this.id = id ; }

      
    public void run() {
        rdv.register() ;
        
    for (int i = 0 ; i < 10 ; i++) {
          System.out.print(id) ; rdv.sync() ;
        }
        rdv.checkout() ;
      }

      
    public static void main (String [] arg) {
        
    int n = 26 ;
        
    for (int i = 0 ; i < n ; i++)
          
    new All((char)('A' + i)).start() ;

      }
    }
    L'affichage attendu est un certain nombre (entre 26 × 10 et 10) de lignes non-vides comportant des lettres distinctes. Chaque lettre apparaissant au total 10 fois nécessairement dans 10 lignes successives.

  8. Le blindage demande de renoncer à la barrière en cas d'exception.
      public void run() {
        rdv.register() ;
        
    try {
          
    for (int i = 0 ; i < 10 ; i++) {
            System.out.print(id) ; rdv.sync() ;
          }
        } 
    catch (Throwable e) { }
        rdv.checkout() ;
      }
    On notera que les exceptions sont toutes attrapées, Throwable étant une classe parente de toutes les exceptions possibles. C'est un peu excessif, on pourrait n'attraper que les exceptions non signalées par le compilateur (classe Error ?).

    On peut aussi utiliser try B finallyC qui spécifie que C sera exécuté que B termine normalement ou par une exception.
      public void run() {
        rdv.register() ;
        
    try {
          
    for (int i = 0 ; i < 10 ; i++) {
            System.out.print(id) ; rdv.sync() ;
          }
        } 
    finally { rdv.checkout() ; }
      }

    On note une subtile différence entre les deux solutions, dans le premier cas, la méthode run termine normalement, dans le second elle termine sur exception. Ici, la fin de run mène à la mort du thread dans les deux cas et ça n'a pas d'importance, il en irait différamment dans une méthode appelée par run, la seconde solution est alors sans doute plus logique.