JetBrains propose, dans un article publié le 27 août 2026, une lecture pratique de trois composants de Project Loom dans IntelliJ IDEA : Virtual Threads, Scoped Values et Structured Concurrency. L’idée fondamentale n’est pas d’ajouter des API distinctes, mais de traiter trois problèmes liés dans les applications Java concurrentes : la scalabilité, la transmission du contexte et la gestion du cycle de vie des threads et des erreurs.
L’article explique que l’écriture de code multithread reste sujette aux fuites de threads, à l’absorption des exceptions, aux conditions de concurrence et aux retards d’annulation. En outre, le recours traditionnel aux pools de threads et à CompletableFuture peut disperser la logique d’annulation et de gestion des erreurs sur plusieurs branches, ce qui augmente le risque de ne pas la mettre à jour lors de l’ajout d’une nouvelle tâche concurrente.
Les threads virtuels réduisent le coût de l’attente
Les threads virtuels reposent sur la JEP 444 et sont stables depuis Java 21. Contrairement aux threads de plateforme liés aux threads du système d’exploitation, les threads virtuels sont gérés par la JVM et peuvent être créés à un coût bien moindre. JetBrains indique que la création d’un thread virtuel prend des microsecondes plutôt que des millisecondes, et que le thread libère le thread de plateforme lorsqu’il se met en attente d’une base de données, d’une connexion réseau, d’un fichier ou d’un mécanisme de synchronisation.
Cela les rend particulièrement adaptés aux charges de travail qui dépendent d’opérations bloquantes, car il devient moins nécessaire de régler à l’avance la taille des pools de threads. L’article mentionne également que Java 24 a introduit, via la JEP 491, une amélioration permettant aux threads virtuels bloqués dans des méthodes ou des instructions synchronized de libérer le thread de plateforme au lieu de le maintenir occupé.
Un contexte partagé sans les problèmes de ThreadLocal
Scoped Values, stables depuis Java 25 conformément à la JEP 506, répondent à un problème différent. Les applications doivent souvent transmettre des données telles qu’un identifiant de session ou un identifiant de traçage à plusieurs parties d’une requête. Cela se faisait généralement au moyen de ThreadLocal, mais ses valeurs peuvent être modifiées et restent liées à la durée de vie du thread à moins d’être supprimées manuellement, ce qui peut entraîner des fuites de mémoire ou des problèmes de sécurité. JetBrains indique que des frameworks tels que Spring peuvent utiliser ThreadLocal en interne, même lorsque le développeur ne l’emploie pas directement.
ScopedValue propose un modèle fondé sur l’association de la valeur une seule fois dans une portée donnée, puis sur sa mise à disposition automatique du code qui s’exécute à l’intérieur de cette portée et son nettoyage à la fin de celle-ci. L’association ne peut pas être modifiée depuis l’intérieur de la portée, et la valeur est transmise aux tâches enfants lorsqu’elle est utilisée avec la concurrence structurée, sans transmission explicite du contexte. En pratique, cela réduit le nombre de points de contrôle que le développeur doit suivre lors de l’exécution de tâches parallèles.
La concurrence structurée lie les tâches à une durée de vie claire
Structured Concurrency, fondée sur la JEP 533, vise les problèmes structurels du code concurrent. Elle reste toutefois à sa septième version d’aperçu dans Java 27 ; JetBrains ne recommande donc pas encore son utilisation dans les environnements de production. Le concept consiste à traiter un ensemble de tâches liées comme une seule unité de travail ayant un propriétaire, une durée de vie et une politique d’échec clairement définis.
Dans l’exemple présenté par JetBrains, l’application récupère en parallèle l’historique des commandes du client et les recommandations de produits afin de construire le profil du client. Avec StructuredTaskScope, il est possible de définir un délai de deux secondes, d’exiger la réussite des deux tâches et d’annuler automatiquement l’autre tâche si l’une d’elles échoue ou si le délai expire. Au lieu de répéter les appels à cancel() dans les branches de traitement des exceptions, la politique d’annulation devient une partie de la portée de la tâche.
L’article explique également un autre cas qui n’exige pas la réussite de toutes les tâches : si l’application obtient les recommandations auprès de deux caches et qu’une seule réponse réussie lui suffit, elle peut utiliser anySuccessfulOrThrow(). Lorsqu’un résultat réussi arrive, la portée est fermée et l’autre tâche est automatiquement annulée ; si les deux tâches échouent, une exception expliquant la cause de l’échec est levée.
Qu’est-ce qui change dans IntelliJ IDEA ?
L’intérêt ne se limite pas à la syntaxe du code. Depuis IntelliJ IDEA 2026.1, les threads virtuels créés à l’intérieur de StructuredTaskScope sont regroupés dans des conteneurs représentant leurs portées, ce qui rend visible dans le débogueur la structure de la relation entre la tâche parente et les tâches enfants. Ainsi, le dump des threads n’affiche pas seulement une liste plate de threads appartenant à un pool général, mais fournit un meilleur indicateur des tâches qui relèvent de la même requête.
Pour essayer ces fonctionnalités, le développeur a besoin de Java 27, qui est une version Early Access selon l’article, et doit régler le niveau du langage afin d’utiliser les fonctionnalités expérimentales. IntelliJ IDEA permet de télécharger un JDK depuis les paramètres du projet et affiche également des indications intégrées lors de l’utilisation d’outils tels que SDKMAN! ou asdf pour gérer les versions du JDK. Une structure initiale de StructuredTaskScope peut être créée à l’aide du modèle de code en direct sts.
La lecture éditoriale de certi.news
Le changement concret réside dans le transfert d’une partie de la gestion de la concurrence, qui relevait auparavant de la responsabilité manuelle du développeur, vers un modèle dans lequel la structure du code exprime la durée de vie de la tâche et sa politique d’échec. Virtual Threads traite le coût de la scalabilité, Scoped Values encadre la transmission du contexte, tandis que Structured Concurrency tente de rendre l’annulation et la propagation des erreurs prévisibles. La combinaison de ces fonctionnalités pourrait réduire le code répétitif dans les applications qui exécutent plusieurs opérations d’attente en parallèle.
Mais les limites de l’évolution sont claires : Structured Concurrency n’est pas encore stable, et Java 27 était une version en accès anticipé au moment de la publication de l’article. L’article de blog ne démontre donc pas que chaque application obtiendra automatiquement une amélioration, et il ne supprime pas la nécessité de tester le comportement des bibliothèques et des frameworks utilisés avec ces modèles. La valeur actuelle pour les développeurs réside dans la compréhension du modèle et son expérimentation en toute sécurité, tout en maintenant les fonctionnalités expérimentales hors de la production jusqu’à la stabilisation de leurs API et l’acquisition d’une expérience opérationnelle suffisante.