↑
CHAPITRE 12.2

Création de threads

Créer et démarrer des threads avec Thread et Runnable
Il existe plusieurs façons de créer des threads en Java. Les deux méthodes principales sont : étendre la classe Thread ou implémenter l'interface Runnable. Cette section vous montre comment créer, démarrer et gérer des threads dans vos programmes Java.

12.2Création de threads

12.2.1 – Méthode 1 : Étendre la classe Thread

La première méthode consiste à créer une classe qui étend la classe Thread et à redéfinir la méthode run().

📝 Structure de base

public class MonThread extends Thread {
    @Override
    public void run() {
        // Code à exécuter dans le thread
        System.out.println("Thread en cours d'exécution");
    }
}

🚀 Utilisation

public class ExempleThread {
    public static void main(String[] args) {
        // Créer une instance du thread
        MonThread thread = new MonThread();
        
        // Démarrer le thread (appelle automatiquement run())
        thread.start();
        
        // Le code continue ici pendant que le thread s'exécute
        System.out.println("Code du thread principal");
    }
}
Important : N'appelez jamais run() directement ! Utilisez toujours start() pour démarrer un thread. Appeler run() directement exécute le code dans le thread actuel, pas dans un nouveau thread.

đź’» Exemple complet : Thread avec boucle

public class ThreadCompteur extends Thread {
    private String nom;
    private int max;
    
    public ThreadCompteur(String nom, int max) {
        this.nom = nom;
        this.max = max;
    }
    
    @Override
    public void run() {
        for (int i = 1; i <= max; i++) {
            System.out.println(nom + " : " + i);
            try {
                Thread.sleep(500);  // Pause de 500ms
            } catch (InterruptedException e) {
                System.out.println(nom + " interrompu");
                return;
            }
        }
        System.out.println(nom + " terminé");
    }
}

// Utilisation
public class TestThreads {
    public static void main(String[] args) {
        ThreadCompteur t1 = new ThreadCompteur("Thread-1", 5);
        ThreadCompteur t2 = new ThreadCompteur("Thread-2", 5);
        
        t1.start();  // Démarrer le premier thread
        t2.start();  // Démarrer le deuxième thread
        
        // Les deux threads s'exécutent en parallèle
    }
}
Résultat possible :
  • Les messages des deux threads seront mĂ©langĂ©s car ils s'exĂ©cutent simultanĂ©ment
  • L'ordre d'affichage peut varier Ă  chaque exĂ©cution
  • Les deux threads s'exĂ©cutent en parallèle, pas sĂ©quentiellement

❌ Limitation de cette approche

Étendre Thread a une limitation : Java ne supporte pas l'héritage multiple. Si votre classe doit déjà étendre une autre classe, vous ne pouvez pas étendre Thread.


12.2.2 – Méthode 2 : Implémenter l'interface Runnable (recommandé)

La méthode recommandée est d'implémenter l'interface Runnable. Cette approche est plus flexible car elle permet à votre classe d'étendre une autre classe si nécessaire.

📝 Structure de base

public class MaTache implements Runnable {
    @Override
    public void run() {
        // Code à exécuter dans le thread
        System.out.println("Tâche en cours d'exécution");
    }
}

🚀 Utilisation

public class ExempleRunnable {
    public static void main(String[] args) {
        // Créer une instance de la tâche
        MaTache tache = new MaTache();
        
        // Créer un thread avec la tâche
        Thread thread = new Thread(tache);
        
        // Démarrer le thread
        thread.start();
    }
}

💻 Exemple complet : Runnable avec paramètres

public class TacheCompteur implements Runnable {
    private String nom;
    private int max;
    
    public TacheCompteur(String nom, int max) {
        this.nom = nom;
        this.max = max;
    }
    
    @Override
    public void run() {
        for (int i = 1; i <= max; i++) {
            System.out.println(nom + " : " + i);
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                System.out.println(nom + " interrompu");
                return;
            }
        }
        System.out.println(nom + " terminé");
    }
}

// Utilisation
public class TestRunnable {
    public static void main(String[] args) {
        TacheCompteur tache1 = new TacheCompteur("Tâche-1", 5);
        TacheCompteur tache2 = new TacheCompteur("Tâche-2", 5);
        
        Thread t1 = new Thread(tache1);
        Thread t2 = new Thread(tache2);
        
        t1.start();
        t2.start();
    }
}

🎯 Avantages de Runnable

  • FlexibilitĂ© : Votre classe peut Ă©tendre une autre classe
  • RĂ©utilisabilitĂ© : Une mĂŞme tâche peut ĂŞtre exĂ©cutĂ©e par plusieurs threads
  • SĂ©paration des responsabilitĂ©s : La tâche (Runnable) est sĂ©parĂ©e du thread (Thread)
  • RecommandĂ© : C'est la mĂ©thode recommandĂ©e par Oracle

12.2.3 – Méthode 3 : Expressions lambda (Java 8+)

Depuis Java 8, vous pouvez utiliser des expressions lambda pour créer des threads de manière concise, car Runnable est une interface fonctionnelle.

📝 Syntaxe avec lambda

// Thread simple avec lambda
Thread thread = new Thread(() -> {
    System.out.println("Thread avec lambda");
});

thread.start();

💻 Exemples variés

Exemple 1 : Thread simple

new Thread(() -> System.out.println("Hello")).start();

Exemple 2 : Thread avec boucle

new Thread(() -> {
    for (int i = 1; i <= 5; i++) {
        System.out.println("Compteur : " + i);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}).start();

Exemple 3 : Plusieurs threads

for (int i = 1; i <= 3; i++) {
    final int numero = i;  // Doit ĂŞtre final ou effectively final
    new Thread(() -> {
        System.out.println("Thread " + numero + " en cours");
    }).start();
}
Variable effectively final : Dans les lambdas, vous ne pouvez utiliser que des variables qui sont final ou "effectively final" (qui ne sont jamais modifiées après leur initialisation).

12.2.4 – Méthodes utiles de la classe Thread

La classe Thread fournit plusieurs méthodes utiles pour contrôler et obtenir des informations sur les threads.

🔧 Méthodes de contrôle

start()

Démarre le thread (appelle run() dans un nouveau thread).

thread.start();  // Démarre le thread

sleep(long millis)

Met le thread en pause pour un nombre de millisecondes.

try {
    Thread.sleep(1000);  // Pause de 1 seconde
} catch (InterruptedException e) {
    e.printStackTrace();
}

join()

Attend que le thread se termine avant de continuer.

Thread thread = new Thread(() -> {
    // Code du thread
});

thread.start();
thread.join();  // Attendre que le thread se termine
System.out.println("Thread terminé");

interrupt()

Interrompt le thread (envoie un signal d'interruption).

thread.interrupt();  // Interrompre le thread

📊 Méthodes d'information

getName() et setName()

Thread thread = new Thread(() -> {});
thread.setName("MonThread");
System.out.println(thread.getName());  // Affiche : MonThread

getId()

long id = thread.getId();  // ID unique du thread

getState()

Thread.State etat = thread.getState();
System.out.println(etat);  // NEW, RUNNABLE, BLOCKED, etc.

isAlive()

boolean vivant = thread.isAlive();  // true si le thread est actif

currentThread()

Thread actuel = Thread.currentThread();  // Thread actuellement exécuté

💡 Points clés à retenir

  • Étendre Thread : Simple mais limite l'hĂ©ritage
  • ImplĂ©menter Runnable : RecommandĂ©, plus flexible
  • Lambda : Syntaxe concise pour les tâches simples
  • start() : DĂ©marre le thread (ne pas appeler run() directement)
  • sleep() : Met en pause le thread
  • join() : Attend la fin du thread
  • interrupt() : Interrompt le thread
Conseil pratique : Utilisez toujours Runnable (ou lambda) plutôt que d'étendre Thread. C'est plus flexible et c'est la pratique recommandée. Réservez l'extension de Thread uniquement si vous avez besoin de modifier le comportement de la classe Thread elle-même.