← CertifHub
Java 6 juin 2026 · 7 · par L'équipe CertifApp

Virtual Threads (Project Loom) : exploiter la concurrence légère en Java

Découvrez comment les virtual threads, introduits par Project Loom, simplifient le modèle de concurrence en Java et comment les utiliser efficacement pour vos certifications.

Pourquoi les virtual threads changent la donne

Les virtual threads (ou fibres légères) sont des implémentations de java.lang.Thread gérées par la JVM plutôt que par le système d’exploitation. Contrairement aux threads classiques, ils sont créés en quelques microsecondes, consomment très peu de mémoire et peuvent être mis en pause sans bloquer un thread du système. Cette approche résout les limites classiques du modèle thread‑per‑request : surcharge de création, contention sur le pool de threads et complexité du code asynchrone.

Créer et piloter des virtual threads

Depuis Java 21 (ou Java 19 en preview), la création d’un virtual thread se fait via la méthode statique Thread.startVirtualThread(Runnable). Le code suivant montre un serveur HTTP minimal qui lance un virtual thread par requête :

import java.io.*;
import java.net.*;

public class SimpleLoomServer {
    public static void main(String[] args) throws IOException {
        ServerSocket server = new ServerSocket(8080);
        System.out.println("Listening on port 8080");
        while (true) {
            Socket client = server.accept();
            Thread.startVirtualThread(() -> handle(client));
        }
    }

    private static void handle(Socket client) {
        try (BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
             BufferedWriter out = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()))) {
            // Lecture rapide de la première ligne de la requête
            String requestLine = in.readLine();
            System.out.println("Received: " + requestLine);
            // Réponse fixe
            out.write("HTTP/1.1 200 OK\r\n");
            out.write("Content-Type: text/plain\r\n\r\n");
            out.write("Hello from a virtual thread!\n");
            out.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Ce modèle évite les pools de threads explicites : chaque connexion reçoit son propre virtual thread, ce qui rend le code synchrone et lisible tout en conservant une scalabilité comparable à une solution basée sur CompletableFuture.

Intégration avec les API existantes

Les virtual threads sont compatibles avec les API bloquantes classiques (InputStream.read, Socket.accept, JDBC). Aucun changement d’interface n’est nécessaire ; la JVM intercepte les appels bloquants et les convertit en opérations non bloquantes sous le capot. Cependant, il est recommandé :

  • D’éviter les blocs synchronisés (synchronized, ReentrantLock) qui peuvent entraîner des thread‑starvation si un grand nombre de virtual threads conteste les mêmes ressources.
  • De privilégier les structures de données sans contention (ConcurrentHashMap, LongAdder).
  • De ne pas mélanger virtual et platform threads dans le même pool sans justification, afin de garder une visibilité claire sur la charge réelle du système.

Cas d’usage typiques pour les certifications

  1. Micro‑services à haute concurrence – Un service qui doit gérer des milliers de requêtes simultanées peut être implémenté avec un simple ExecutorService basé sur des virtual threads :
    ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();
    for (int i = 0; i < 10_000; i++) {
        executor.submit(() -> callRemoteService());
    }
    executor.shutdown();
    
  2. Traitement de flux I/O – Lire un grand nombre de fichiers simultanément sans recourir à NIO :
    try (Stream<Path> files = Files.list(Path.of("/data"))) {
        files.forEach(path -> Thread.startVirtualThread(() -> processFile(path)));
    }
    
  3. Tests de charge – Simuler des utilisateurs virtuels avec un seul appel à Thread.startVirtualThread par utilisateur, ce qui réduit la consommation de mémoire pendant les tests de performance.

Bonnes pratiques et limites actuelles

  • Surveiller la mémoire : bien que chaque virtual thread consomme ~ 2 KB de stack natif, le nombre total peut tout de même impacter la heap si des objets lourds sont créés dans chaque thread.
  • Utiliser StructuredTaskScope pour gérer les groupes de virtual threads et garantir la terminaison propre des tâches :
    try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
        for (int i = 0; i < 5; i++) {
            scope.fork(() -> computePart(i));
        }
        scope.join(); // attend que toutes les tâches soient terminées
    }
    
  • Éviter les appels bloquants externes non‑interceptables : les bibliothèques natives qui ne respectent pas les conventions de blocage peuvent bloquer le carrier thread sous‑jacent, annulant les bénéfices de Loom.
  • Préparer les certifications : les examinateurs s’attendent à ce que vous maîtrisiez les différences entre Thread.ofVirtual() et Thread.ofPlatform(), la création de scopes structurés, et la stratégie de migration d’un code existant vers les virtual threads.

Conclusion

Les virtual threads de Project Loom offrent une manière simple et performante de gérer la concurrence massive en Java. En combinant la syntaxe synchrone familière avec la légèreté des fibres, ils permettent d’écrire du code lisible, testable et scalable. Pour les certifications Java, connaître les API Thread.startVirtualThread, ExecutorService dédié et StructuredTaskScope constitue un atout déterminant.

Envie d’aller plus loin avec CertifApp ?

Découvrir CertifApp