Bonjours à tous,

Je débute dans les Treads, et dans un but pédagogique je doit réaliser l'exercice suivant :

<italique>
Un groupe d'amis décide de faire des promenades, cependant les membres du groupe ne marchent pas à la même vitesse. Ils ont donc prévu de faire 5 tours d’un parcours cyclique en forêt avec 2 rendez-vous : marche individuelle sur la partie A, attente au RDV1, puis marche individuelle sur la partie B, puis RDV2, etc. Chaque marcheur sera représenté par un thread Java avec sa propre IHM (Frame + textArea). Ces threads passeront un temps aléatoire dans la partie A qui pourra être matérialisé par plusieurs tirages aléatoires. (Il s’agit de faire 1000 mètres en additionnant des tirages aléatoires de 100m. Les marcheurs se synchronisent au rendez-vous RDV1 (donc les premiers arrivés attendent le dernier). Puis ils passeront un temps aléatoire dans la partie B. Ils seront synchronisés au rendez-vous RDV2. Ensuite chaque thread recommence la partie A du parcours en forêt.

Rédigez une classe Marcheur (avec IHM) représentant les activités d'un marcheur.
Rédigez une classe RDV qui permet l'organisation des rendez-vous. Cette classe dispose d'un compteur représentant le nombre de personnes attendues au RDV. Chaque marcheur incrémente ce compteur à son arrivée au RDV et se met en sommeil avec l’aide de la méthode wait(). Le dernier marcheur ne doit pas utiliser la méthode wait() mais faire appel à la méthode notifyAll() pour réveiller tous les autres marcheurs.
Rédigez la classe Principale qui initialise le programme avec 5 marcheurs puis 10 marcheurs.
</italique>

Voici mes classes (c'est un peu crade je sais mais je peaufinerai quand ça marchera ) :

Marcheur.java
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
 
public class Marcheur implements Runnable{
    private String label;
    private Color couleur;
    private int position;
    private int arrivee;//La position de l'arrivé en mètre
 
    private JFrame fen;
    private JLabel avancement;//Pour afficher dans l'interface graphique l'avancement actuel
 
    //static Marcheur dernier_arrive;
    static RDV prochain_rdv;
    static RDV rdv1;
    static RDV rdv2;
 
    public Marcheur(String label, Color couleur, int arrive) {
        //On commence par récupérer des infos sur le prochain rdv pour les afficher
        String label_prochain_rdv = null;
 
        if( prochain_rdv != null){
            label_prochain_rdv = "Prochain RDV : " + prochain_rdv.getLabel_rdv();
        }else{
            label_prochain_rdv = "Prochain RDV : inconnu";
        }
 
        this.label = label;
        this.couleur = couleur;
        this.position = 0;
        this.arrivee = arrive;
        this.avancement = new JLabel("Marcheur " + label + " " + label_prochain_rdv + " " + position + " / "+arrivee);
 
 
        //Construction de la fenetre
        fen = new JFrame();
        fen.getContentPane().add(avancement);
        fen.setTitle("Test marcheur");
        fen.setSize(190, 80);
        fen.setLocation(200, 100+(Integer.parseInt(label)*80));
 
        fen.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        fen.setVisible(true);
 
 
    }
 
    public String getLabel(){
        return this.label;
    }
 
    /**Permet de réinitialiser un Marcheur pour qu'il soit prêt à repartir
    */
    public void initialiser(){
        this.position = 0;
        //this.avancement.setText("Marcheur " + label + " " + prochain_rdv.getLabel_rdv() + " " + position + " / "+arrivee);
    }
 
    //Pour rensigner les rdv connu de tous les marcheurs (variable static)
    public void initialiserRDV(RDV rdvA, RDV rdvB, RDV proch_rdv){
        Marcheur.rdv1 = rdvA;
        Marcheur.rdv2 = rdvB;
        Marcheur.prochain_rdv = proch_rdv;
    }
 
    //Pour tous les marcheur, indique le prochain rendez-vous
    public void setProchainRDV(RDV rdv){
        Marcheur.prochain_rdv = rdv;
    }
 
    public boolean estArrive(){
        return arrivee - position == 0;
    }
 
    public int alea(int valeur){
        Random generator = new Random();
        return generator.nextInt(valeur+1);
    }
 
    public void pause(int valeur){
        try {
            Thread.sleep(valeur);
        } catch (InterruptedException ex) {
            Logger.getLogger(Marcheur.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
 
    private void avancer(){
        int distance_parcourue = alea(3)*100;//On avance par 100 mètres
        this.position += distance_parcourue;
 
        //On arrête le marcheur à l'arrivée si il est en position de la dépasser. 
        if( position > arrivee){
            position = arrivee;
        }
        avancement.setText("Marcheur " + label + " " +prochain_rdv.getLabel_rdv() + " " + position + " / "+arrivee);
    }
 
    /**Pour passer du rdv 1 au 2 ou vice versa */
    void changer_rdv(){
        if( Marcheur.prochain_rdv == Marcheur.rdv1){
            Marcheur.prochain_rdv = Marcheur.rdv2;
        }else{
            Marcheur.prochain_rdv = Marcheur.rdv1;
        }
        Marcheur.prochain_rdv.nb_marcheur_arrive = 0;//De nouveau, plus personne n'est arrivé
    }
 
    //Gère l'arrivé au rdv, si on est le dernier on fait un notify sur les autres, sinon on attends
    synchronized void arriver(){
        if( Marcheur.prochain_rdv.tous_arrive()){
            this.notifyAll();
            System.out.println("\n RDV suivant ! \n");
            //changer_rdv();
 
        }else{
            try {
                this.wait();
            } catch (InterruptedException ex) {
                Logger.getLogger(Marcheur.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }
 
    void aller_au_rdv(){
        while( !estArrive()){
            avancer();
            pause(1000);
        }
        System.out.println(label + "est arrivé.");
        Marcheur.prochain_rdv.marcheur_arrive(this);//On indique au rdv qu'on est arrive
        this.arriver();
    }
 
    @Override
    public void run(){
        //aller_au_rdv();
        for(int i=0 ; i<5 ; i++){
            aller_au_rdv();
            this.position = 0;//Si on execute cette ligne, c'est qu'on a été reveillé eet qu'on est passé au rdv suivant
        }
    }
}
RDV.java

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
 
public class RDV{
    final String label_rdv;
    final int nb_marcheur_total;
    int nb_marcheur_arrive;
    //List <Marcheur>liste_marcheur;
 
    RDV(int nb_marcheur_total, String label){
        this.nb_marcheur_total = nb_marcheur_total;
        //this.liste_marcheur = new ArrayList<Marcheur>();
        this.nb_marcheur_arrive = 0;
        this.label_rdv = label;
    }
 
    public String getLabel_rdv() {
        return label_rdv;
    }
 
    //Cette méthode doit absolument être synchronisé, sinon grave incohérence
    synchronized boolean tous_arrive(){
        return nb_marcheur_arrive == nb_marcheur_total;
    }
 
    synchronized void marcheur_arrive(Marcheur arrivant){
        nb_marcheur_arrive++;
    }
}
Et enfin, la classe principale qui construit les différents objet puis lance le tout.

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
 
public class Principal {
    Marcheur[] marcheurs;
    Thread[] threads;
    RDV rdv1, rdv2;
 
    Principal(int nb_marcheur){
        marcheurs = new Marcheur[nb_marcheur];
        threads = new Thread[5];
 
        //Création des 2 lieux de rendez-vous
        rdv1 = new RDV(nb_marcheur, "rdv1");
        rdv2 = new RDV(nb_marcheur, "rdv2");
 
        //On cré chaque marcheur, on lui associe le rdv1, et on lui associe un thread
        for(int i=0 ; i<nb_marcheur ; i++){
            marcheurs[i] = new Marcheur(i+"", Color.RED, 1000);
            threads[i]   = new Thread(marcheurs[i]);
        }
        marcheurs[0].initialiserRDV(rdv1, rdv2, rdv1);
 
        rdv1 = new RDV(nb_marcheur, "rdv1");
        rdv2 = new RDV(nb_marcheur, "rdv2");
    }
 
    void lancer(){
        for(int i=0 ; i<marcheurs.length ; i++){
            threads[i].start();
        }
    }
 
    public static void main(String[] args){
        Principal p = new Principal(5);
        p.lancer();
    }
}
Sauf que voila, tout marche mais au bout du premier rdv les Thread en attentes ne sont pas réveillé...
Seul le dernier Thread (qui fait le notifyAll() ) repart.
Et je ne comprends pas pourquoi.
J'ai beau relire la doc, le cours, il y a un truc qui m'a échappé et que je n'ai pas saisi...

Pourriez-vous m'éclairer ?

Merci d'avance.