↑
CHAPITRE 12.1

Introduction aux threads

Comprendre la programmation concurrente et multi-thread en Java
Les threads permettent d'exécuter plusieurs tùches simultanément dans un programme Java. Cette capacité de programmation concurrente est essentielle pour créer des applications performantes et réactives. Ce chapitre vous introduit aux concepts fondamentaux des threads, à leur création, à leur gestion, et aux problÚmes de synchronisation qui peuvent survenir.

12.1Introduction aux threads

12.1.1 – Qu'est-ce qu'un thread ?

Un thread (fil d'exécution) est une unité d'exécution indépendante dans un programme Java. Un programme peut avoir plusieurs threads qui s'exécutent simultanément, permettant ainsi d'effectuer plusieurs tùches en parallÚle.

🔍 Concept fondamental

Par défaut, un programme Java s'exécute dans un seul thread (le thread principal ou "main thread"). Cependant, vous pouvez créer plusieurs threads pour exécuter différentes parties de votre code simultanément.

Analogie :
  • Programme sĂ©quentiel : Comme un cuisinier qui fait une tĂąche Ă  la fois (prĂ©parer les lĂ©gumes, puis cuire, puis servir)
  • Programme multi-thread : Comme plusieurs cuisiniers travaillant en parallĂšle (un prĂ©pare les lĂ©gumes pendant qu'un autre cuit la viande)

đŸ’» Exemple : Programme sĂ©quentiel vs Multi-thread

Programme séquentiel (un seul thread)

public class ProgrammeSequentiel {
    public static void main(String[] args) {
        // TĂąche 1
        for (int i = 1; i <= 5; i++) {
            System.out.println("TĂąche 1 : " + i);
            try {
                Thread.sleep(1000);  // Pause de 1 seconde
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        
        // Tùche 2 (attend que la tùche 1 soit terminée)
        for (int i = 1; i <= 5; i++) {
            System.out.println("TĂąche 2 : " + i);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
// Résultat : Tùche 1 complÚte, puis Tùche 2 complÚte (séquentiel)

Programme multi-thread

public class ProgrammeMultiThread {
    public static void main(String[] args) {
        // Créer et démarrer le thread 1
        Thread thread1 = new Thread(() -> {
            for (int i = 1; i <= 5; i++) {
                System.out.println("TĂąche 1 : " + i);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        
        // Créer et démarrer le thread 2
        Thread thread2 = new Thread(() -> {
            for (int i = 1; i <= 5; i++) {
                System.out.println("TĂąche 2 : " + i);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        
        thread1.start();  // Démarrer le thread 1
        thread2.start();  // Démarrer le thread 2
        
        // Les deux threads s'exécutent en parallÚle
    }
}
// Résultat : Les tùches 1 et 2 s'exécutent simultanément (mélangées)
Différence clé :
  • SĂ©quentiel : Les tĂąches s'exĂ©cutent une aprĂšs l'autre (total : ~10 secondes)
  • Multi-thread : Les tĂąches s'exĂ©cutent en parallĂšle (total : ~5 secondes)
  • Dans le programme multi-thread, les messages des deux threads peuvent ĂȘtre mĂ©langĂ©s car ils s'exĂ©cutent simultanĂ©ment

🎯 Avantages des threads

  • Performance : Utilisation efficace des processeurs multi-cƓurs
  • RĂ©activitĂ© : Interface utilisateur qui reste rĂ©active pendant les opĂ©rations longues
  • ParallĂ©lisme : Traitement simultanĂ© de plusieurs tĂąches
  • EfficacitĂ© : Meilleure utilisation des ressources systĂšme

⚠ DĂ©fis des threads

  • Synchronisation : GĂ©rer l'accĂšs concurrent aux ressources partagĂ©es
  • Race conditions : ProblĂšmes quand plusieurs threads modifient la mĂȘme variable
  • Deadlocks : Blocage mutuel entre threads
  • ComplexitĂ© : Plus difficile Ă  dĂ©boguer qu'un programme sĂ©quentiel

12.1.2 – Thread principal (Main Thread)

Chaque programme Java démarre avec au moins un thread : le thread principal (main thread). C'est ce thread qui exécute la méthode main().

🔍 Identifier le thread principal

public class ThreadPrincipal {
    public static void main(String[] args) {
        // Obtenir une référence au thread actuel
        Thread threadActuel = Thread.currentThread();
        
        // Afficher les informations du thread
        System.out.println("Nom du thread : " + threadActuel.getName());
        System.out.println("ID du thread : " + threadActuel.getId());
        System.out.println("Priorité : " + threadActuel.getPriority());
        System.out.println("État : " + threadActuel.getState());
        
        // Le thread principal s'appelle "main"
        // Affiche : Nom du thread : main
    }
}
Caractéristiques du thread principal :
  • Nom : "main"
  • PrioritĂ© : 5 (prioritĂ© normale par dĂ©faut)
  • État : RUNNABLE quand il s'exĂ©cute
  • DĂ©marre automatiquement avec l'exĂ©cution du programme

📊 États d'un thread

Un thread peut ĂȘtre dans diffĂ©rents Ă©tats pendant son cycle de vie :

  • NEW : Thread créé mais pas encore dĂ©marrĂ©
  • RUNNABLE : Thread exĂ©cutable (en cours d'exĂ©cution ou prĂȘt Ă  ĂȘtre exĂ©cutĂ©)
  • BLOCKED : Thread bloquĂ© en attendant un verrou (lock)
  • WAITING : Thread en attente indĂ©finie
  • TIMED_WAITING : Thread en attente avec un dĂ©lai
  • TERMINATED : Thread terminĂ©
Thread thread = new Thread(() -> {
    System.out.println("Thread en cours d'exécution");
});

System.out.println("État avant start() : " + thread.getState());  // NEW

thread.start();
System.out.println("État aprùs start() : " + thread.getState());  // RUNNABLE

// Attendre que le thread se termine
try {
    thread.join();
    System.out.println("État aprùs join() : " + thread.getState());  // TERMINATED
} catch (InterruptedException e) {
    e.printStackTrace();
}

12.1.3 – Cas d'usage des threads

Les threads sont utilisés dans de nombreux contextes pour améliorer les performances et la réactivité des applications.

🌐 Applications web

Les serveurs web gĂšrent plusieurs requĂȘtes simultanĂ©ment, chaque requĂȘte Ă©tant traitĂ©e dans un thread sĂ©parĂ©.

Exemple : Un serveur web peut traiter 100 requĂȘtes simultanĂ©ment en utilisant 100 threads diffĂ©rents, au lieu d'attendre que chaque requĂȘte soit terminĂ©e avant de traiter la suivante.

🎼 Applications graphiques

Les interfaces utilisateur utilisent des threads pour rester réactives pendant les opérations longues.

// Exemple conceptuel : Interface utilisateur
// Thread 1 : Interface utilisateur (reste réactive)
// Thread 2 : Calculs lourds en arriĂšre-plan

// Sans threads : L'interface se fige pendant les calculs
// Avec threads : L'interface reste réactive pendant les calculs

📊 Traitement de donnĂ©es

Le traitement parallĂšle de grandes quantitĂ©s de donnĂ©es peut ĂȘtre accĂ©lĂ©rĂ© en divisant le travail entre plusieurs threads.

🔄 TĂąches pĂ©riodiques

Les threads peuvent ĂȘtre utilisĂ©s pour exĂ©cuter des tĂąches pĂ©riodiques (sauvegardes automatiques, nettoyage, etc.).

💡 Points clĂ©s Ă  retenir

  • Thread : UnitĂ© d'exĂ©cution indĂ©pendante
  • Thread principal : ExĂ©cute la mĂ©thode main()
  • Multi-threading : ExĂ©cution simultanĂ©e de plusieurs threads
  • Avantages : Performance, rĂ©activitĂ©, parallĂ©lisme
  • DĂ©fis : Synchronisation, race conditions, complexitĂ©
  • États : NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED