Concurrence en Java : des threads classiques aux goroutines et async/await
\n\nJava 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\nSi 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\nPourquoi la concurrence est-elle importante pour un développeur Java moderne ?
\n\nImaginez 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\nLes 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\nNiveau 1 : Les threads classiques (Thread) — les fondations
\n\nUn 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\nVoici un exemple simple de création d'un thread :
\n\npublic 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\nAvantages :
\n- \n
- Simplicité de création — new Thread(() -> { ... }).start(); \n
- Gestion directe du cycle de vie. \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
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\nNiveau 2 : Les threads virtuels (Project Loom) — les goroutines en Java
\n\nSi 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\nLes 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\nExemple de création d'un thread virtuel :
\n\npublic 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\nIncroyable, n'est-ce pas ?