"Si un trabajador quiere hacer bien su trabajo, primero debe afilar sus herramientas." - Confucio, "Las Analectas de Confucio. Lu Linggong"
Página delantera > Programación > Explorando la fijación en el mecanismo de subproceso virtual de JVM

Explorando la fijación en el mecanismo de subproceso virtual de JVM

Publicado el 2024-11-08
Navegar:220

Los subprocesos virtuales de Java ofrecen una alternativa ligera a los subprocesos del sistema operativo tradicional, lo que permite una gestión eficiente de la concurrencia. Pero comprender su comportamiento es crucial para un rendimiento óptimo. Esta publicación de blog profundiza en la fijación, un escenario que puede afectar la ejecución de subprocesos virtuales, y explora técnicas para monitorearlo y abordarlo.

Hilos virtuales: un enfoque de concurrencia ligero

Los subprocesos virtuales de Java son entidades administradas que se ejecutan sobre los subprocesos del sistema operativo subyacente (subprocesos portadores). Proporcionan una manera más eficiente de manejar la concurrencia en comparación con la creación de numerosos subprocesos del sistema operativo, ya que incurren en una menor sobrecarga. La JVM asigna dinámicamente subprocesos virtuales a subprocesos portadores, lo que permite una mejor utilización de los recursos.

  • Administrado por JVM: a diferencia de los subprocesos del sistema operativo que son administrados directamente por el sistema operativo, los subprocesos virtuales los crea y programa la máquina virtual Java (JVM). Esto permite un control y una optimización más detallados dentro del entorno JVM.

  • Reducción de gastos generales: la creación y administración de subprocesos virtuales genera una sobrecarga significativamente menor en comparación con los subprocesos del sistema operativo. Esto se debe a que la JVM puede gestionar un conjunto más grande de subprocesos virtuales de manera eficiente, utilizando una cantidad menor de subprocesos del sistema operativo subyacente.

  • Compatibilidad con código existente: los subprocesos virtuales están diseñados para integrarse perfectamente con el código Java existente. Se pueden utilizar junto con subprocesos del sistema operativo tradicional y funcionan dentro de construcciones familiares como Executor y ExecutorService para la gestión concurrente.

La siguiente figura muestra la relación entre los subprocesos virtuales y los subprocesos de la plataforma:

Exploring Pinning in JVM


Fijar: cuando un hilo virtual se atasca

La fijación ocurre cuando un hilo virtual queda vinculado a su hilo portador. Básicamente, esto significa que el hilo virtual no puede ser reemplazado (cambiado a otro hilo portador) mientras está en un estado anclado. Estos son escenarios comunes que activan la fijación:

  • Bloques y métodos sincronizados: la ejecución de código dentro de un bloque o método sincronizado conduce a la fijación. Esto garantiza el acceso exclusivo a recursos compartidos, evitando problemas de corrupción de datos.

Ejemplo de código:

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 



En este ejemplo, cuando un hilo virtual ingresa al bloque sincronizado, queda anclado a su hilo portador, pero esto no siempre es cierto. La palabra clave sincronizada de Java por sí sola no es suficiente para provocar la fijación de subprocesos en subprocesos virtuales. Para que se produzca la fijación de subprocesos, debe haber un punto de bloqueo dentro de un bloque sincronizado que haga que un subproceso virtual active el estacionamiento y, en última instancia, no permita el desmontaje de su subproceso portador. La fijación de subprocesos podría provocar una disminución en el rendimiento, ya que anularía los beneficios del uso de subprocesos ligeros/virtuales.

Cada vez que un hilo virtual encuentra un punto de bloqueo, su estado pasa a ESTACIONAMIENTO. Esta transición de estado se indica invocando el método 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);
  }
}

Echemos un vistazo a un ejemplo de código para ilustrar este concepto:

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 



  • Métodos nativos/funciones externas: la ejecución de métodos nativos o funciones externas también puede causar fijación. Es posible que la JVM no pueda administrar de manera eficiente el estado del subproceso virtual durante estas operaciones.

Supervisión de fijación con -Djdk.tracePinnedThreads=full

El indicador -Djdk.tracePinnedThreads=full es un argumento de inicio de JVM que proporciona información de seguimiento detallada sobre la fijación de subprocesos virtuales. Cuando está habilitado, registra eventos como:

  • ID del hilo virtual involucrado en la fijación
  • ID del hilo del operador al que está anclado el hilo virtual
  • Seguimiento de pila que indica la sección de código que provoca la fijación

Utilice esta marca con prudencia únicamente durante las sesiones de depuración, ya que introduce una sobrecarga de rendimiento.

  1. Compile nuestro código de demostración:

    javac Main.java
    
  2. Inicie el código compilado con el indicador -Djdk.tracePinnedThreads=full:

    java -Djdk.tracePinnedThreads=full Main
    
  3. Observe el resultado en la consola, que muestra información detallada sobre la fijación de subprocesos virtuales:

    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) 
    
    

Fijación de fijación con cerraduras reentrantes

La fijación es un escenario indeseable que impide el rendimiento de los subprocesos virtuales. Las cerraduras reentrantes sirven como una herramienta eficaz para contrarrestar el bloqueo. Así es como puedes usar bloqueos reentrantes para mitigar situaciones de fijación:

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 



En el ejemplo actualizado, utilizamos un ReentrantLock en lugar de un bloque sincronizado. El hilo puede adquirir el bloqueo y liberarlo inmediatamente después de completar su operación, lo que potencialmente reduce la duración de la fijación en comparación con un bloque sincronizado que podría mantener el bloqueo durante un período más largo.

En conclusión

Los hilos virtuales de Java son un testimonio de la evolución y las capacidades del lenguaje. Ofrecen una alternativa nueva y liviana a los subprocesos del sistema operativo tradicional, proporcionando un puente hacia una gestión eficiente de la concurrencia. Tomarse el tiempo para profundizar y comprender conceptos clave como la fijación de subprocesos puede dotar a los desarrolladores del conocimiento necesario para aprovechar todo el potencial de estos subprocesos livianos. Este conocimiento no solo prepara a los desarrolladores para aprovechar las próximas funciones, sino que también les permite resolver problemas complejos de control de concurrencia de manera más efectiva en sus proyectos actuales.

Declaración de liberación Este artículo se reproduce en: https://dev.to/yanev/exploring-pinning-in-jvms-virtual-thread-mechanism-5h13?1 Si hay alguna infracción, comuníquese con [email protected] para eliminarla.
Último tutorial Más>

Descargo de responsabilidad: Todos los recursos proporcionados provienen en parte de Internet. Si existe alguna infracción de sus derechos de autor u otros derechos e intereses, explique los motivos detallados y proporcione pruebas de los derechos de autor o derechos e intereses y luego envíelos al correo electrónico: [email protected]. Lo manejaremos por usted lo antes posible.

Copyright© 2022 湘ICP备2022001581号-3