BT

Diffuser les Connaissances et l'Innovation dans le Développement Logiciel d'Entreprise

Contribuez

Sujets

Sélectionner votre région

Accueil InfoQ Actualités JEP 425 : Threads Virtuels Pour Offrir Un Débit Amélioré

JEP 425 : Threads Virtuels Pour Offrir Un Débit Amélioré

La JEP 425, Virtual Threads (Preview), a été promue du statut Proposed to Target à Targeted pour le JDK 19. Cette JEP, sous l'égide du projet Loom, introduit les threads virtuels. Ces threads légers visent à réduire considérablement l'effort d'écriture, de maintenance et d'observation des applications simultanées à haut débit sur la plate-forme Java. Il s'agit d'une fonctionnalité en preview.

Java a été la première plate-forme de programmation grand public à intégrer les threads dans le langage de base en tant qu'unité de programmation parallèle. Les threads Java classiques (une instance de java.lang.Thread) sont un wrapper un à un sur les threads du système d'exploitation (OS) (également appelés threads de plate-forme). D'autre part, les threads virtuels sont des implémentations légères de la classe Thread que le JDK fournit, plutôt que le système d'exploitation. Les threads virtuels utilisent le thread de la plate-forme pour exécuter leur code, mais il ne capture pas le thread du système d'exploitation pendant toute la durée de vie du code. Cela permet à de nombreux threads virtuels d'exécuter leur code Java sur le même thread du système d'exploitation.

Les threads virtuels présentent de nombreux avantages. Surtout, cela rend la création de threads bon marché et contribue à augmenter le débit des applications. Les applications serveur gèrent aujourd'hui les demandes simultanées des utilisateurs en déléguant chacune à une unité d'exécution indépendante, c'est-à-dire un thread de la plate-forme. Ce style de programmation thread-per-request est facile à comprendre, facile à programmer et facile à déboguer et à profiler. Cependant, les threads de la plate-forme sont limités en nombre car le JDK implémente des threads en tant que wrapper autour des threads du système d'exploitation. Ainsi, lorsqu'une application doit évoluer pour augmenter le débit, elle ne parvient pas à le faire avec les threads de la plate-forme. Désormais, comme un grand nombre de threads virtuels sont faciles à créer, le style de programmation thread-per-request atténue ce goulot d'étranglement d'évolutivité.

En outre, lorsque le code s'exécutant sur un thread virtuel appelle une I/O bloquante, le thread virtuel est automatiquement suspendu jusqu'à ce qu'il puisse être repris ultérieurement. Pendant ce temps, d'autres threads virtuels peuvent prendre le relais sur le thread du système d'exploitation et continuer à exécuter leur code. Au contraire, le thread du système d'exploitation serait bloqué dans une situation similaire, ce qui n'est pas souhaitable en raison de leurs limitations.

Les threads virtuels prennent en charge les variables locales au thread, les blocs de synchronisation, les interruptions de thread, etc. Pour les développeurs Java, cela signifie que les threads virtuels sont simplement des threads bon marché et abondants, et que l'approche de programmation ne change pas du tout. Le code Java existant écrit ciblant les threads classiques peut facilement s'exécuter dans un thread virtuel sans modifications.

Les développeurs qui souhaitent expérimenter les threads virtuels peuvent télécharger la version early-access du JDK 19 et se familiariser avec elle. La classe Thread fournit une nouvelle méthode, startVirtualThread(Runnable), qui prend un argument de type Runnable et crée des threads virtuels. Considérez l'exemple suivant :

public class Main {
    public static void main(String[] args) throws InterruptedException {
        var vThread = Thread.startVirtualThread(() -> {
            System.out.println("Hello from the virtual thread");
        });

        vThread.join();
    }
}

Comme il s'agit d'une fonctionnalité en preview, le développeur devra fournir le flag --enable-preview pour compiler ce code comme indiqué dans la commande suivante :

javac --release 19 --enable-preview Main.java

Le même flag est également requis pour exécuter le programme :

java --enable-preview Main

Cependant, on peut l'exécuter directement en utilisant le lanceur de code source. Dans ce cas, la ligne de commande serait :

java --source 19 --enable-preview Main.java

L'option jshell est également disponible, mais nécessite également l'activation des fonctionnalités en preview :

jshell --enable-preview

Alors que Thread.startVirtualThread(Runnable) est le moyen pratique de créer un thread virtuel, de nouvelles API telles que Thread.Builder, Thread.ofVirtual() et Thread.ofPlatform() ont été ajoutées pour créer des threads virtuels et de la plate-forme.

Un thread virtuel ne peut pas être créé à l'aide du constructeur public. Il fonctionne comme un thread démon avec la priorité NORM_PRIORITY. Ainsi, le Thread.setPriority(int) et Thread.setDaemon(boolean) ne peuvent pas modifier la priorité d'un thread virtuel ou le transformer en un thread non démon. De plus, les threads actifs portent des threads virtuels, ils ne peuvent donc faire partie d'aucun ThreadGroup. L'utilisation de Thread.getThreadGroup() renvoie "VirtualThreads".

Les threads virtuels ne doivent jamais être regroupés car chacun est destiné à exécuter une seule tâche au cours de sa durée de vie. Au lieu de cela, le modèle est la création sans contrainte de threads virtuels. A cet effet, un exécuteur illimité a été ajouté. Il est accessible via une nouvelle méthode de fabrique Executors.newVirtualThreadPerTaskExecutor(). Ces méthodes permettent la migration et l'interopérabilité avec le code existant qui utilise des pools de threads et un ExecutorService. Considérez l'exemple suivant :

import java.time.Duration;
import java.util.concurrent.Executors;
import java.util.stream.IntStream;

public class Main {
    public static void main(String[] args) {
        
        try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
            IntStream.range(0, 10_000).forEach(i -> {
                executor.submit(() -> {
                    Thread.sleep(Duration.ofSeconds(1));
                    return i;
                });
            });
        }
    }
}

Le scheduler par défaut pour les threads virtuels est le scheduler de work-stealing introduit dans ForkJoinPool.

Les développeurs intéressés par une plongée approfondie dans les threads virtuels et apprendre l'histoire peuvent écouter le Podcast InfoQ et une session YouTube par Ron Pressler, membre consultant de l'équipe technique d'Oracle et chef de projet de projet Loom.

 

Au sujet de l’Auteur

Evaluer cet article

Pertinence
Style

Contenu Éducatif

BT