JEP 425, Virtual Threads (Preview)
Contexte
Les threads virtuels ont été proposés dans le JDK 19. Ils sont maintenant intégré dans le build 22 du JDK 19 en accès anticipé. Cela correspond à une proposition incluant les travaux du projet Loom
Le thread au niveau de la JVM sont basés sur les threads systèmes. C’est à dire que c’est le système qui s’occupe de planifier leur execution. Cela implique que le nombre de thread est limité par le système.
Objectif
L’objectif est d’avoir un thread léger qui permettent d’avoir des milliers et des millions de thread afin de réaliser des traitements concurrents.
Les threads classiques s’appellent maintenant les threads plateformes ("a plateform thread") afin de les différencier des threads virtuels.
Ce qui est intéressant, c’est que les threads virtuels héritent de la même classe java.lang.Thread
.
En revanche, il n’y a pas de constructeurs. En effet, la mode est de passer de plus en plus par des fabriques de méthodes. Pour cela, nous avons la méthode statique : Thread.startVirtualThread()
Le thread est démarré avec une instance de l’interface java.lang.Runnable
.
Ainsi, nous pouvons écrire la classe suivante :
class HelloRunnable implements Runnable {
public void run() {
System.out.println(Thread.currentThread() + " dit Coucou");
}
}
Utilisation
Nous pouvons tester les threads virtuels avec la commande jshell
. Vu que les threads virtuels sont en mode aperçu. Il est nécessaire d’activer les aperçus avec l’option --enable-preview
bin/jshell --enable-preview
Maintenant, nous allons pouvoir créer notre classe HelloRunnable
suivi d’une instance
var inst = new HelloRunnable();
Il nous reste à démarrer le thread virtuel.
Thread.startVirtualThread(inst);
A noter, que nous pouvons utiliser la méthode Thread.ofVirtual()
qui utilise le pattern Builder
Thread.ofVirtual.start(inst);
Cette méthode offre deux avantages :
-
Nous avons une méthode similaire pour les threads plateformes
Thread.ofPlatform.start(inst);
-
Nous pouvons créer une instance sans démarrer le thread (ou en tout cas sans le démarrer tout de suite.)
Thread courant = Thread.ofVirtual.unstarted(inst);
courant.start();
Pour rappel, Java 8 est passé par là avec les lambas. Donc nous pouvons écrire tout simplement :
Thread.ofVirtual().start(() -> {
System.out.println(Thread.currentThread() + " dit Coucou");
});
Remarques
En exécutant le code ci-dessus, nous obtenons la sortie suivante
VirtualThread[#25]/runnable@ForkJoinPool-1-worker-1 dit Coucou
$1 ==> VirtualThread[#25]/runnable
Le #25 est une sorte de compteur de thread virtuel. Si nous exécutons de nouveau la même commande, nous obtiendrons la sortie suivante
VirtualThread[#26]/runnable@ForkJoinPool-1-worker-1 dit Coucou
$1 ==> VirtualThread[#26]/runnable
C’est normal car nous lançons un nouveau thread virtuel. Ce qui veut dire que la première fois, il y a eu 24 thread virtuels exécutés avant notre premier appel.
Qui les utilisent ? La JVM elle-même.
Compléments sur l’API
-
Il est possible de savoir si nous sommes dans un thread virtuel ou non. Nous avons la méthode
Thread.isVirtual()
qui renvoie un booléen. -
Les méthodes
Thread.join()
etThread.sleep()
possède une surcharge prenant en paramètre une instance deDuration
. -
La méthode
Thread.getId()
est dépréciée. Il faut passer par la méthodeThread.threadId()
. Ce dernier renvoie un identifiant. -
La méthode
Thread.getAllStackTraces()
retourne une map de toutes les threads plateforme et non tous les threads comme son nom le laisse penser.
Cela s’explique car nous pouvons avoir des millions de threads virtuels donc il n’y a pas de sens de retourner une map aussi grosse.
Difference sur l’API
-
Les threads virtuels sont forcément des threads daemon. La méthode
Thread.setDaemon()
n’a pas d’effet.
Pensez à cela pour les conditions d’arrêt de la JVM. En effet, il faut au moins un thread plateforme sinon la JVM s’arrête.
-
Dans le même style, la priorité est fixée à Thread.NORM_PRIORITY. La méthode
Thread.setPriority()
n’a pas d’effet. -
Les méthodes
stop(), suspend() et resume()
lèvent une exception lors de leur invocation si c’est un thread virtuel.
Pour rappel, ces méthodes sont déjà dépréciés au moins depuis le JDK 6.
-
Dans le même sens de l’histoire, il n’y a pas de permissions si le
SecurityManager
est activé.
Pour rappel, ce dernier est déprécié pour suppression depuis le JDK 17. Plus d’informations, dans ce billet JDK 17 Nouveautés
Références
Moteur de recherche
"Eduquer, ce n'est pas remplir des vases mais c'est d'allumer des feux." - Michel Montaigne
Billets récents
- Eclipse plante systématiquement sous Debian (et autres distribution Linux)
- JEP 463, Implicitly Declared Classes and Instance Main Methods (Second Preview)
- Debian - Montée de version de Debian 11 (Bullseye) à Debian 12 (Bookworm)
- JEP 451, Prepare to Disallow the Dynamic Loading of Agents
- JEP 444, Virtual Threads