Exemple: Train entre deux gares 

Un train circule entre deux gares "A" et "B". Selon l'horaire, le train reste pendant un certain temps à chaque gare et se déplace pendant un certain temps jusqu'à l'autre gare.  Il transfère des passagers qui voyagent vers l'une ou l'autre gare (générés au hasard).  Il est permis d'embarquer au maximum N passagers. Modélisez la situation en Java.

Ressource - moniteur. Le moniteur résume la situation à travers des variables privées telles que: où se trouve le train, dans quelle direction il se déplace, le nombre de passagers à bord, combien de passagers attendent dans les deux gares, le nombre maximum de passagers dans le train. Il fournit des méthodes publiques synchronisées pour modifier les variables.

onA, onB - Le train arrété  à la gare  A ou B
passAB,passBA - nombre des voyageurs dans le train;
passMax -Macimale nombre de voyageurs dans le train;
leaveA(), leaveB(), arriveA(), arriveB() - Départ ou arrivé de (à) la gare;
taketA(), taketB(), leavetA(), leavetB(), - les voyageurs montent ou descendent de train.
public class Monitor {
    private boolean onA, onB;
    private int passAB,passBA, passMax;
    public Monitor(int passMax ){
        onA=true;
        System.out.println("Train on A");
        onB = false;
        passAB=passBA=0;
        this.passMax=passMax;
    }
    public synchronized void leaveA(){
        onA=false;
        System.out.println("\t\t\t\tTrain travelling A ->B");
    }
    public synchronized void arriveB(){
        System.out.println("\t\t\t\tTrain arrive B");
        onB=true;
        notifyAll();
    }
    public synchronized void leaveB(){
        onB = false;
        System.out.println("\t\t\t\tTrain travelling B ->A");
    }
    public synchronized void arriveA(){
        System.out.println("\t\t\t\tTrain arrive A");
        onA=true;
        notifyAll();
    }
    public synchronized void taketA(){
        while(!onA||((passAB+passBA)>=passMax)){
            System.out.println("\t\t"+Thread.currentThread().getName()+" waiting train");
            try{     wait();   }
            catch(InterruptedException e){
                System.err.println(e);
            }
        }
        System.out.print(Thread.currentThread().getName()+" get the train;");
        passAB++;
        if(passAB+passBA >= passMax) System.out.print(" train is full");
        System.out.println("\t"+passAB+" passengers in the train traveling A-> B");
    }
    public synchronized void taketB(){
        while(!onB||((passAB+passBA)>=passMax)){
            System.out.println("\t\t"+Thread.currentThread().getName()+" waiting train");
            try{     wait();   }
            catch(InterruptedException e){
                System.err.println(e);
            }
        }
        System.out.print(Thread.currentThread().getName()+" get the train;");
        passBA++;
        if(passAB+passBA >= passMax) System.out.print(" train is full");
        System.out.println("\t"+passBA+" passengers in the train traveling B-> A");
    }
    public synchronized void leavetA(){
        while(!onA){
            //System.out.println("\t"+Thread.currentThread().getName()+" traveling in the train");
            try{     wait();   }
            catch(InterruptedException e){
                System.err.println(e);
            }
        }
        System.out.print(Thread.currentThread().getName()+" leaving the train and going home; ");
        if(passBA>0)passBA--;
        System.out.println("\t"+passBA+" passengers B-> A still in the train");
        notifyAll();
    }
    public synchronized void leavetB(){
        while(!onB){
            //System.out.println(Thread.currentThread().getName()+" traveling in the train");
            try{     wait();   }
            catch(InterruptedException e){
                System.err.println(e);
            }
        }
        System.out.print(Thread.currentThread().getName()+" leaving the train and going home; ");
        if(passAB>0)passAB--;
        System.out.println("\t"+passAB+" passengers  A-> B still in the train");
        notifyAll();
    }
}

Train - thread
Le train va 3 fois de la gare A vers la gare B et à l'envers.
public class Train extends Thread{
    Monitor mt;
    public Train(Monitor mt){
        this.mt=mt;    
    }
    public void run(){
        for(int i=0;i<3;i++){
            try{
                sleep(1000);
            }
            catch(InterruptedException e){}
            mt.leaveA();
            try{
                sleep(2000);
            }
            catch(InterruptedException e){}   
            mt.arriveB();
            try{
                sleep(1000);
            }
            catch(InterruptedException e){}
            mt.leaveB();
            try{
                sleep(2000);
            }
            catch(InterruptedException e){}   
            mt.arriveA();
        }
    }
}

Voyageur  - thread
aToB - direction de voyage  - dans le nom de voyageur.
public class Pass extends Thread{
    boolean aToB;
    static int num=1;
    Monitor mt;
    String name;
    Pass(Monitor mt,boolean aToB){
        name = "pass"+num++ +(aToB?"(A to B)":"(B to A)");
        super.setName(name);
        this.mt=mt;
        this.aToB = aToB;       
    }
    public void run(){
        if(aToB){
            mt.taketA();
            mt.leavetB();
        }
        else{
            mt.taketB();
            mt.leavetA();
        }
    }
}

Démarrage de modèle
20 voyageurs  généré par hasard;
 5 voyageurs maximum dans le train.
public class Circ {
    public static void main(String arg[]){
        Monitor mt = new Monitor(5);
        Train train = new Train(mt);
        train.start();
        for(int i=0;i<20;i++){
            (new Pass(mt,Math.random()>0.5?true:false)).start();
        }
    }
}

Dans ce modèle si le temps de rester sur une gare de train et trop court, le train démarre sans attendre que tous les passagers sont descendus!

Modifiez le modèle afin que le train ne peut démarrer
1. s'il y a des passagers qui ne sont pas encore descendus
2. ou bien il n'est pas plein et il y a encore des passagers à la gare!