Classes Runnable abstraites pour les événements de threads
Jusqu'à présent, nous avons vu comment créer des threads simples qui exécutent du code une seule fois. Cependant, de nombreuses applications ont besoin de threads qui répondent à des événements à intervalles réguliers ou en continu. Une approche est de créer une classe Runnable abstraite qui encapsule la logique de gestion des événements.
Concept général
L'idée est de créer une classe abstraite qui implémente Runnable et qui offre une méthode abstraite que les sous-classes doivent implémenter.
Nouveau mot clé - volatile
Le mot clé volatile sert à indiquer que cette variable pourrait être lue par plusieurs threads simultanément. Ce mot clé s'assure que la lecture de cette variable sera la bonne. Cependant, il n'assure pas l'intégrité de la modification de la variable.
Voici un exemple avec un timer qui se déclenche à intervalles réguliers :
On pourrait ensuite utiliser la classe comme suit :
En définissant la méthode tick() dans l'application principale, on pourra décider ce qui se passe à chaque seconde.
Exemple avec une nouvelle classe
Créons une classe qui affiche un message toutes les 2 secondes :
public class MessageTimer extends RunnableTimer {
private int compteur = 0;
public MessageTimer() {
super(2000); // Appeler tick() toutes les 2 secondes
}
@Override
public void tick() {
compteur++;
System.out.println("Tick #" + compteur);
}
}
Ensuite, utilisons-la dans notre application :
public class App {
public static void main(String[] args) {
MessageTimer timer = new MessageTimer();
Thread thread = new Thread(timer);
thread.start();
// Arrêter quand l'utilisateur appuie sur ENTER
IO.readln("** Appuyez sur ENTER pour arrêter **\n");
// Arrêter le timer
timer.arreter();
System.out.println("Timer arrêté");
}
}
Résultat :
Points importants
Gestion de l'InterruptedException
Bien que nous n'affichions pas l'exception dans la méthode run(), il est possible que le thread soit interrompu en cas d'arrêt forcé. Une meilleure pratique serait de :
@Override
public void run() {
while (!doitArreter) {
try {
Thread.sleep(delay);
this.tick();
} catch (InterruptedException e) {
System.err.println("Timer interrompu");
break;
}
}
}
Il pourrait ensuite être arrêté de l'intérieur via un méthode abstraite arreter() et Thread.currentThread().interrupt() ou de l'extérieur en utilisant monThread.interrupt().
Créer une application de discussion multithread
Nous allons procéder à créer une petite application de discussion multithread. Vous pouvez utiliser netcat comme client. Votre application doit avoir les fonctionnalités suivantes :
1. Permettre la connexion de plusieurs clients
1. Lorsqu'un client envoie un message, tous les utilisateurs devront recevoir ce message
Comment procéder?
- Utilisez une classe
Runnableabstraite avec les méthodes abstraites suivantes : void messageEnvoye(String message);void clientDeconnecte(Socket client);- Dans vos threads:
- quand un message est reçu, l'envoyer à tous en appelant la méthode
messageEnvoye() - quand un client déconnecte, informer le thread principal en appelant la méthode
clientDeconnecte() - Le thread principal garde en mémoire tous les sockets des clients et les utilise pour faire un broadcast aux autres.
Exemple
Défi supplémentaire
- Faites en sorte que les BROADCAST ne soient pas reçus par celui qui a envoyé le message