Concurrence et multithreading en Java : guide complet

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course
Here is the translated HTML content in French, with all HTML tags preserved and only the text content translated. ```html

Concurrence et multithreading en Java : de la théorie à la pratique



Dans le monde moderne du logiciel, les performances des applications dépendent directement de la capacité à utiliser efficacement les ressources du processeur. La concurrence et le multithreading en Java sont des concepts clés qui permettent d'exécuter plusieurs tâches simultanément, d'accélérer le traitement des données et de créer des interfaces utilisateur réactives. Dans cet article, nous allons détailler les mécanismes de base du multithreading en Java, apprendre à créer et gérer des threads, et examiner les meilleures pratiques pour éviter les erreurs courantes.



Qu'est-ce qu'un thread et comment le créer en Java ?



Un thread est un processus léger qui s'exécute au sein d'une seule application. Chaque thread possède sa propre pile d'appels et peut fonctionner indépendamment des autres threads. En Java, il existe deux méthodes principales pour créer un thread.



Méthode 1 : Héritage de la classe Thread

public class MyThread extends Thread {    @Override    public void run() {        System.out.println("Le thread " + getName() + " est lancé !");    }

public static void main(String[] args) { MyThread thread = new MyThread(); thread.start(); // Lancement du thread }}


Méthode 2 : Implémentation de l'interface Runnable

public class MyRunnable implements Runnable {    @Override    public void run() {        System.out.println("Le thread s'exécute via Runnable");    }

public static void main(String[] args) { Thread thread = new Thread(new MyRunnable()); thread.start(); }}


Il est recommandé d'utiliser la deuxième méthode car elle ne nécessite pas d'héritage et permet d'implémenter plusieurs interfaces simultanément.



Synchronisation des threads : éviter les race conditions



Lorsque plusieurs threads accèdent simultanément à des données partagées, une condition de concurrence (race condition) se produit. Pour éviter cela, Java fournit des mécanismes de synchronisation.



Le mot-clé synchronized

Bloque l'accès à une méthode ou à un bloc de code pour les autres threads jusqu'à ce que le thread actuel ait terminé son exécution :

public class Counter {    private int count = 0;

public synchronized void increment() { count++; }

public synchronized int getCount() { return count; }}


Verrous avec Lock

Un mécanisme plus flexible que synchronized. Il permet de définir des délais d'attente et de tenter d'obtenir un verrou sans bloquer :

import java.util.concurrent.locks.ReentrantLock;

public class SafeCounter { private final ReentrantLock lock = new ReentrantLock(); private int count = 0;

public void increment() { lock.lock(); try { count++; } finally { lock.unlock(); // Toujours libérer le verrou } }}


Pool de threads et ExecutorService



Créer un nouveau thread pour chaque tâche est une opération coûteuse. Pour une gestion efficace des threads, utilisez ExecutorService du package java.util.concurrent.



import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;

public class ThreadPoolExample { public static void main(String[] args) { // Créer un pool de 4 threads ExecutorService executor = Executors.newFixedThreadPool(4);

for (int i = 0; i < 10; i++) { final int taskId = i; executor.submit(() -> { System.out.println("La tâche " + taskId + " s'exécute dans " + Thread.currentThread().getName()); }); }

executor.shutdown(); // Arrêter le pool après l'exécution de toutes les tâches }}


Types principaux de pools :