„Wenn ein Arbeiter seine Arbeit gut machen will, muss er zuerst seine Werkzeuge schärfen.“ – Konfuzius, „Die Gespräche des Konfuzius. Lu Linggong“
Titelseite > Programmierung > Erkunden des Pinnings im virtuellen Thread-Mechanismus der JVM

Erkunden des Pinnings im virtuellen Thread-Mechanismus der JVM

Veröffentlicht am 08.11.2024
Durchsuche:215

Die virtuellen Threads von Java bieten eine leichte Alternative zu herkömmlichen Betriebssystem-Threads und ermöglichen eine effiziente Parallelitätsverwaltung. Für eine optimale Leistung ist es jedoch entscheidend, ihr Verhalten zu verstehen. Dieser Blog-Beitrag befasst sich mit dem Pinning, einem Szenario, das sich auf die Ausführung virtueller Threads auswirken kann, und untersucht Techniken zur Überwachung und Behebung dieses Problems.

Virtuelle Threads: Ein leichter Parallelitätsansatz

Die virtuellen Threads von Java sind verwaltete Einheiten, die auf den zugrunde liegenden Betriebssystem-Threads (Träger-Threads) ausgeführt werden. Sie bieten im Vergleich zur Erstellung zahlreicher Betriebssystem-Threads eine effizientere Möglichkeit, Parallelität zu handhaben, da sie einen geringeren Overhead verursachen. Die JVM ordnet virtuelle Threads dynamisch Träger-Threads zu und ermöglicht so eine bessere Ressourcennutzung.

  • Von der JVM verwaltet: Im Gegensatz zu Betriebssystem-Threads, die direkt vom Betriebssystem verwaltet werden, werden virtuelle Threads von der Java Virtual Machine (JVM) erstellt und geplant. Dies ermöglicht eine detailliertere Steuerung und Optimierung innerhalb der JVM-Umgebung.

  • Reduzierter Overhead: Das Erstellen und Verwalten virtueller Threads verursacht im Vergleich zu Betriebssystem-Threads einen deutlich geringeren Overhead. Dies liegt daran, dass die JVM einen größeren Pool virtueller Threads effizient verwalten kann und dabei eine kleinere Anzahl zugrunde liegender Betriebssystem-Threads nutzt.

  • Kompatibilität mit vorhandenem Code: Virtuelle Threads sind so konzipiert, dass sie nahtlos in vorhandenen Java-Code integriert werden können. Sie können neben herkömmlichen Betriebssystem-Threads verwendet werden und arbeiten mit den bekannten Konstrukten wie Executor und ExecutorService für die gleichzeitige Verwaltung.

Die folgende Abbildung zeigt die Beziehung zwischen virtuellen Threads und Plattform-Threads:

Exploring Pinning in JVM


Pinning: Wenn ein virtueller Thread hängen bleibt

Pinning tritt auf, wenn ein virtueller Thread an seinen Träger-Thread gebunden wird. Dies bedeutet im Wesentlichen, dass der virtuelle Thread nicht vorzeitig freigegeben (auf einen anderen Träger-Thread umgeschaltet) werden kann, während er sich in einem angehefteten Zustand befindet. Hier sind häufige Szenarien, die das Anheften auslösen:

  • Synchronisierte Blöcke und Methoden: Das Ausführen von Code innerhalb eines synchronisierten Blocks oder einer synchronisierten Methode führt zum Pinning. Dies stellt den exklusiven Zugriff auf gemeinsam genutzte Ressourcen sicher und verhindert Datenkorruptionsprobleme.

Codebeispiel:

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; i 



Wenn in diesem Beispiel ein virtueller Thread in den synchronisierten Block eintritt, wird er an seinen Träger-Thread angeheftet, aber das ist nicht immer der Fall. Das synchronisierte Schlüsselwort von Java allein reicht nicht aus, um das Anheften von Threads in virtuellen Threads zu bewirken. Damit das Thread-Pinning erfolgen kann, muss es einen Blockierungspunkt innerhalb eines synchronisierten Blocks geben, der dazu führt, dass ein virtueller Thread das Parken auslöst und letztendlich das Aufheben der Bereitstellung von seinem Träger-Thread verhindert. Das Anheften von Threads kann zu Leistungseinbußen führen, da dadurch die Vorteile der Verwendung leichter/virtueller Threads zunichte gemacht werden.

Immer wenn ein virtueller Thread auf einen Blockierungspunkt stößt, wechselt sein Zustand in PARKING. Dieser Zustandsübergang wird durch Aufrufen der VirtualThread.park()-Methode angezeigt:

// 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);
  }
}

Sehen wir uns ein Codebeispiel an, um dieses Konzept zu veranschaulichen:

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 



  • Native Methoden/Fremdfunktionen: Das Ausführen nativer Methoden oder Fremdfunktionen kann ebenfalls zum Anheften führen. Die JVM ist möglicherweise nicht in der Lage, den Status des virtuellen Threads während dieser Vorgänge effizient zu verwalten.

Überwachen des Pinnings mit -Djdk.tracePinnedThreads=full

Das Flag -Djdk.tracePinnedThreads=full ist ein JVM-Startargument, das detaillierte Ablaufverfolgungsinformationen zum Anheften virtueller Threads bereitstellt. Wenn es aktiviert ist, protokolliert es Ereignisse wie:

  • Virtuelle Thread-ID, die am Anheften beteiligt ist
  • Träger-Thread-ID, an die der virtuelle Thread angeheftet ist
  • Stack-Trace, der den Codeabschnitt angibt, der das Pinning verursacht

Verwenden Sie dieses Flag nur während Debugging-Sitzungen mit Bedacht, da es zu einem Leistungsaufwand führt.

  1. Kompilieren Sie unseren Democode:

    javac Main.java
    
  2. Starten Sie den kompilierten Code mit der Flagge -Djdk.tracePinnedThreads=full:

    java -Djdk.tracePinnedThreads=full Main
    
  3. Beobachten Sie die Ausgabe in der Konsole, die detaillierte Informationen zum Anheften virtueller Threads zeigt:

    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) 
    
    

Fixierung mit wiedereintretenden Sperren beheben

Pinning ist ein unerwünschtes Szenario, das die Leistung virtueller Threads beeinträchtigt. Wiedereintrittssperren dienen als wirksames Mittel, um dem Pinning entgegenzuwirken. So können Sie Reentrant-Sperren verwenden, um Pinning-Situationen zu entschärfen:

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; i 



Im aktualisierten Beispiel verwenden wir einen ReentrantLock anstelle eines synchronisierten Blocks. Der Thread kann die Sperre erwerben und sofort nach Abschluss seines Vorgangs freigeben, wodurch möglicherweise die Dauer des Fixierens im Vergleich zu einem synchronisierten Block verkürzt wird, der die Sperre möglicherweise länger hält.

Abschließend

Die virtuellen Threads von Java sind ein Zeugnis für die Entwicklung und die Fähigkeiten der Sprache. Sie bieten eine frische, leichte Alternative zu herkömmlichen Betriebssystem-Threads und schlagen eine Brücke zu einem effizienten Parallelitätsmanagement. Wenn Sie sich die Zeit nehmen, tiefer zu graben und Schlüsselkonzepte wie Thread-Pinning zu verstehen, können Entwickler das Know-how erwerben, um das volle Potenzial dieser leichtgewichtigen Threads auszuschöpfen. Dieses Wissen bereitet Entwickler nicht nur auf die Nutzung kommender Funktionen vor, sondern versetzt sie auch in die Lage, komplexe Probleme der Parallelitätskontrolle in ihren aktuellen Projekten effektiver zu lösen.

Freigabeerklärung Dieser Artikel ist abgedruckt unter: https://dev.to/yanev/exploring-pinning-in-jvms-virtual-thread-mechanism-5h13?1 Bei Verstößen wenden Sie sich bitte an [email protected], um ihn zu löschen
Neuestes Tutorial Mehr>

Haftungsausschluss: Alle bereitgestellten Ressourcen stammen teilweise aus dem Internet. Wenn eine Verletzung Ihres Urheberrechts oder anderer Rechte und Interessen vorliegt, erläutern Sie bitte die detaillierten Gründe und legen Sie einen Nachweis des Urheberrechts oder Ihrer Rechte und Interessen vor und senden Sie ihn dann an die E-Mail-Adresse: [email protected] Wir werden die Angelegenheit so schnell wie möglich für Sie erledigen.

Copyright© 2022 湘ICP备2022001581号-3