Threads, goroutines et async/await en Java : écrire du code concurrent correctement

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

Concurrence en Java : des threads classiques aux goroutines et async/await

\n\n

Java est un langage qui, depuis sa création, sait travailler avec plusieurs tâches simultanément. Mais le monde ne s'arrête pas là. Aujourd'hui, nous allons parler de la concurrence en Java — des bons vieux threads (Thread) aux threads virtuels (goroutines de Project Loom) en passant par l'approche asynchrone avec async/await (via CompletableFuture).

\n\n

Si vous codez en Java et souhaitez que votre serveur ne « ralentisse » pas sous charge, tout en gardant un code lisible, cet article est pour vous. C'est parti !

\n\n

Pourquoi la concurrence est-elle importante pour un développeur Java moderne ?

\n\n

Imaginez que votre site traite 10 000 requêtes par seconde. Si chaque requête est exécutée séquentiellement, les utilisateurs attendront une éternité. La concurrence en Java permet d'exécuter plusieurs tâches « simultanément », en utilisant efficacement les ressources du processeur.

\n\n

Les applications modernes ne sont pas de simples CRUD. Ce sont des microservices, du traitement de flux de données, du WebSocket, de l'analyse en temps réel. Sans comprendre le multithreading Java, vous risquez d'écrire un code qui plantera avec une OutOfMemoryError ou qui fonctionnera comme un escargot.

\n\n

Niveau 1 : Les threads classiques (Thread) — les fondations

\n\n

Un thread en Java est l'abstraction la plus basse pour exécuter du code en parallèle. Chaque thread est un processus « léger » distinct au sein du système d'exploitation.

\n\n

Voici un exemple simple de création d'un thread :

\n\n
public class ThreadExample {\n    public static void main(String[] args) {\n        Thread thread = new Thread(() -> {\n            for (int i = 0; i < 5; i++) {\n                System.out.println("Bonjour depuis le thread : " + i);\n                try {\n                    Thread.sleep(1000);\n                } catch (InterruptedException e) {\n                    Thread.currentThread().interrupt();\n                }\n            }\n        });\n        thread.start();\n        System.out.println("Le thread principal continue son travail");\n    }\n}
\n\n

Avantages :

\n
    \n
  • Simplicité de création — new Thread(() -> { ... }).start();
  • \n
  • Gestion directe du cycle de vie.
  • \n
\n\n

Inconvénients :

\n
    \n
  • La création d'un thread est une opération coûteuse (surcharge de la pile, changement de contexte).
  • \n
  • Limitation du nombre : 10 000 threads peuvent tuer votre JVM.
  • \n
  • Complexité de synchronisation : deadlock, race condition.
  • \n
\n\n

L'approche classique est adaptée aux petites tâches, mais pas aux applications à forte charge. C'est là que les threads virtuels en Java viennent à la rescousse.

\n\n

Niveau 2 : Les threads virtuels (Project Loom) — les goroutines en Java

\n\n

Si vous avez entendu parler des goroutines en Go, les threads virtuels Java sont presque la même chose. Ils sont apparus dans Java 21 (Project Loom) et changent complètement la donne.

\n\n

Les threads virtuels sont des threads « légers » gérés par la JVM, et non par le système d'exploitation. On peut en créer des millions, et ils consomment un minimum de mémoire.

\n\n

Exemple de création d'un thread virtuel :

\n\n
public class VirtualThreadExample {\n    public static void main(String[] args) throws InterruptedException {\n        // Création de 100 000 threads virtuels\n        var threads = new Thread[100_000];\n        for (int i = 0; i < threads.length; i++) {\n            threads[i] = Thread.startVirtualThread(() -> {\n                // Simulation d'un travail avec I/O bloquant\n                try {\n                    Thread.sleep(1000);\n                } catch (InterruptedException e) {\n                    Thread.currentThread().interrupt();\n                }\n            });\n        }\n        for (Thread t : threads) {\n            t.join();\n        }\n        System.out.println("Tous les threads virtuels sont terminés !");\n    }\n}
\n\n

Incroyable, n'est-ce pas ?

Blogs

Book Recommendations