C’est parce qu’il est impossible en Java qu’un Thread puisse gérer le cycle de vie d’un autre Thread (c’est à dire le killer, le mettre en pause etc…).
D’ailleurs, la méthode sleep() de la classe Thread est static ! Autrement dit, un Thread ne peut que s’endormir lui même. Il ne peut pas endormir un autre thread.
Il n’y a pas de solution "miracle" à ce genre de problème. J’entends par là que le développement des solutions robustes est complexe.
Pour que tes Threads puissent interagir les uns avec les autres, ils doivent communiquer leurs "intentions".
L’idée est de créer une classe gérant la vie de ton thread Monstre
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 | public class MonsterRunnable implements Runnable {
private volatile int sleep = 0; // La variable indique le temps d'endormissement en millisecondes. 0 signifie qu'il n'est pas nécéssaire de s'endormir.
// On utilise également "volatile" car la variable dois être lue par deux threads différents.
// De même, on utilise un int pour que les affectations soient atomiques (ce ne serait pas forcément le cas avec un long de 64 bits)
public void monsterSleep(int sleep) {
this.sleep = sleep;
}
@Override
public void run() {
while(true) {
if( this.sleep > 0) { // Si il faut s'endormir
Thread.sleep((long) this.sleep);
this.sleep = 0; // On remet à 0 pour indiquer qu'il n'est plus nécessaire de dormir
}
... // le reste de tes actions dans la boucle
}
}
}
|
Le thread principal peut alors endormir le monstre thread :
| public void run() {
/*
* Après traitement, met en pause le thread de
* monstre, et non pas le thread principal
*/
monster.monsterSleep(2500);
}
|
Il y a toutefois quelques limitations. Comme tu le vois, la boucle du Runnable ne test s’il faut s’endormir qu’au début de chaque tour de boucle. Si l’appel à monsterSleep() a lieu pendant le traitement, ce traitement devra obligatoirement se terminer avant que le thread ne s’endorme.
Cet inconvénient est également un avantage ! On s’assure qu’aucun traitement important ne pourra être interrompu en plein milieu.
Les mécanismes fournis par Java pour arrêter un thread, avec interrupt() et interrupted(), fonctionnent exactement sur le même principe.
Voici la modification à apporter à ton Runnable pour qu’on puisse l’arrêter proprement.
1
2
3
4
5
6
7
8
9
10
11
12
13 | @Override
public void run() {
while(true) {
if( Thread.interrupted() ) { // Si il a été demandé d'arrêter le thread
return; // sort de la boucle, le Thread s'arrête
}
... // le reste de tes actions dans la boucle
}
}
|
On peut alors arrêter le thread proprement:
| monster.interrupt(); // le thread va terminer son traitement en cours et s'arrèter
|