Les threads virtuels de Java offrent une alternative légère aux threads de système d'exploitation traditionnels, permettant une gestion efficace de la concurrence. Mais comprendre leur comportement est crucial pour des performances optimales. Cet article de blog se penche sur l'épinglage, un scénario qui peut avoir un impact sur l'exécution des threads virtuels, et explore les techniques pour le surveiller et y remédier.
Les threads virtuels de Java sont des entités gérées qui s'exécutent au-dessus des threads du système d'exploitation sous-jacents (threads porteurs). Ils offrent un moyen plus efficace de gérer la concurrence par rapport à la création de nombreux threads de système d'exploitation, car ils entraînent une surcharge moindre. La JVM mappe dynamiquement les threads virtuels aux threads porteurs, permettant une meilleure utilisation des ressources.
Gérés par la JVM : contrairement aux threads du système d'exploitation qui sont directement gérés par le système d'exploitation, les threads virtuels sont créés et planifiés par la machine virtuelle Java (JVM). Cela permet un contrôle et une optimisation plus précis au sein de l'environnement JVM.
Surcharge réduite : la création et la gestion de threads virtuels entraînent une surcharge considérablement inférieure à celle des threads du système d'exploitation. En effet, la JVM peut gérer efficacement un plus grand pool de threads virtuels, en utilisant un plus petit nombre de threads du système d'exploitation sous-jacents.
Compatibilité avec le code existant : les threads virtuels sont conçus pour être intégrés de manière transparente au code Java existant. Ils peuvent être utilisés avec les threads de système d'exploitation traditionnels et fonctionner dans les constructions familières telles que Executor et ExecutorService pour la gestion simultanée.
La figure ci-dessous montre la relation entre les threads virtuels et les threads de plateforme :
L'épinglage se produit lorsqu'un thread virtuel est lié à son thread porteur. Cela signifie essentiellement que le thread virtuel ne peut pas être préempté (basculé vers un autre thread porteur) lorsqu'il est dans un état épinglé. Voici les scénarios courants qui déclenchent l'épinglage :
Exemple de code :
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Main { public static void main(String[] args) throws InterruptedException { final Counter counter = new Counter(); Runnable task = () -> { for (int i = 0; iDans cet exemple, lorsqu'un thread virtuel entre dans le bloc synchronisé, il est épinglé sur son thread porteur, mais ce n'est pas toujours vrai. Le mot-clé synchronisé de Java ne suffit pas à lui seul à provoquer l'épinglage de threads dans les threads virtuels. Pour que l'épinglage de thread se produise, il doit y avoir un point de blocage dans un bloc synchronisé qui provoque le déclenchement du parcage d'un thread virtuel et interdit finalement le démontage de son thread porteur. L'épinglage de threads pourrait entraîner une diminution des performances, car cela annulerait les avantages de l'utilisation de threads légers/virtuels.
Chaque fois qu'un thread virtuel rencontre un point de blocage, son état passe à PARKING. Cette transition d'état est indiquée en invoquant la méthode VirtualThread.park() :
// JDK core code void park() { assert Thread.currentThread() == this; // complete immediately if parking permit available or interrupted if (getAndSetParkPermit(false) || interrupted) return; // park the thread setState(PARKING); try { if (!yieldContinuation()) { // park on the carrier thread when pinned parkOnCarrierThread(false, 0); } } finally { assert (Thread.currentThread() == this) && (state() == RUNNING); } }Jetons un coup d'œil à un exemple de code pour illustrer ce concept :
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Main { public static void main(String[] args) { Counter counter = new Counter(); Runnable task = () -> { for (int i = 0; i
L'indicateur -Djdk.tracePinnedThreads=full est un argument de démarrage JVM qui fournit des informations de traçage détaillées sur l'épinglage des threads virtuels. Lorsqu'il est activé, il enregistre des événements tels que :
Utilisez cet indicateur judicieusement pendant les sessions de débogage uniquement, car il introduit une surcharge de performances.
Compilez notre code de démonstration :
javac Main.java
Démarrez le code compilé avec l'indicateur -Djdk.tracePinnedThreads=full :
java -Djdk.tracePinnedThreads=full Main
Observez le résultat dans la console, qui affiche des informations détaillées sur l'épinglage des threads virtuels :
Thread[#29,ForkJoinPool-1-worker-1,5,CarrierThreads] java.base/java.lang.VirtualThread$VThreadContinuation.onPinned(VirtualThread.java:183) java.base/jdk.internal.vm.Continuation.onPinned0(Continuation.java:393) java.base/java.lang.VirtualThread.parkNanos(VirtualThread.java:621) java.base/java.lang.VirtualThread.sleepNanos(VirtualThread.java:791) java.base/java.lang.Thread.sleep(Thread.java:507) Counter.increment(Main.java:38)
L'épinglage est un scénario indésirable qui entrave les performances des threads virtuels. Les verrous réentrants constituent un outil efficace pour contrecarrer le blocage. Voici comment utiliser les verrous réentrants pour atténuer les situations d'épinglage :
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.locks.ReentrantLock; public class Main { public static void main(String[] args) { Counter counter = new Counter(); Runnable task = () -> { for (int i = 0; iDans l'exemple mis à jour, nous utilisons un ReentrantLock au lieu d'un bloc synchronisé. Le thread peut acquérir le verrou et le libérer immédiatement après avoir terminé son opération, réduisant potentiellement la durée de l'épinglage par rapport à un bloc synchronisé qui pourrait maintenir le verrou pendant une période plus longue.
En conclusion
Les threads virtuels de Java témoignent de l'évolution et des capacités du langage. Ils offrent une alternative nouvelle et légère aux threads de système d’exploitation traditionnels, offrant ainsi une passerelle vers une gestion efficace de la concurrence. Prendre le temps d'approfondir et de comprendre des concepts clés tels que l'épinglage de threads peut doter les développeurs du savoir-faire nécessaire pour exploiter tout le potentiel de ces threads légers. Ces connaissances préparent non seulement les développeurs à tirer parti des fonctionnalités à venir, mais leur permettent également de résoudre plus efficacement les problèmes complexes de contrôle de concurrence dans leurs projets en cours.
Clause de non-responsabilité: Toutes les ressources fournies proviennent en partie d'Internet. En cas de violation de vos droits d'auteur ou d'autres droits et intérêts, veuillez expliquer les raisons détaillées et fournir une preuve du droit d'auteur ou des droits et intérêts, puis l'envoyer à l'adresse e-mail : [email protected]. Nous nous en occuperons pour vous dans les plus brefs délais.
Copyright© 2022 湘ICP备2022001581号-3