Sincronizado ya no está hinchado, deja de lado su prejuicio cuando conoció por primera vez las cerraduras livianas

prefacio

  • Selección natural, supervivencia del más apto. JDK también se optimiza constantemente. Con respecto a la sincronización interna del bloqueo sincronizado en el JDK, también se optimiza continuamente.Anteriormente, analizamos el bloqueo sesgado para resolver el problema inicial, y la operación de bloqueo ligero nació con la acumulación continua de contención.
  • Sígueme, un agricultor social progresista, te sacará de la crisis.

Cerradura ligera

  • Como se mencionó anteriormente, el bloqueo sesgado solo se generará cuando no haya competencia y el bloqueo sesgado esté activado. Sin embargo, el bloqueo sesgado no se revocará automáticamente. Veamos el siguiente caso
  • La configuración de vm es la siguiente-XX:+UseBiasedLocking -XX:BiasedLockingStartupDelay=0
 public class SimpleTest {
     public static void main(String[] args) {
         SimpleTest test = new SimpleTest();
         System.out.println(ClassLayout.parseInstance(test).toPrintable());
         synchronized (test) {
             System.out.println("hello world");
             System.out.println(ClassLayout.parseInstance(test).toPrintable());
         }
         System.out.println("锁释放后:"+ClassLayout.parseInstance(test).toPrintable());
 ​
     }
 }
复制代码
  • Podemos ver que las marcas en los objetos de prueba de los tres procesos siempre están sesgadas antes del bloqueo, durante el bloqueo y después del bloqueo. Esto significa que no será revocado voluntariamente.

imagen-20211213143811117.png

  • Partiendo de esta premisa, imaginemos que dos hilos se bloquean en el mismo objeto en momentos diferentes, ¿a esto se le llama competencia de recursos? Porque en realidad es interactivo cuando no se ejecuta al mismo tiempo, pero porque el bloqueo sesgado no se libera activamente de forma predeterminada. En el proceso de bloqueo de bloqueo sesgado, el hilo actual se escribe en la marca a través de CAS. Antes de escribir, se compara si la marca del objeto de bloqueo es el hilo actual. Si es consistente con la identificación del subproceso actual, solo se agregará 1 al contador para implementar bloqueos de reentrada.
  • Si es el segundo subproceso, se producirá una incoherencia en el identificador del subproceso, independientemente de si es al mismo tiempo o no. En este momento, el candado sesgado se actualizará a un candado ligero. Este proceso de actualización también es un proceso muy problemático. La JVM en realidad necesita encontrar un punto seguro (es decir, el punto de tiempo de inactividad del subproceso), primero revocar el bloqueo de polarización y luego activar el bloqueo ligero.

Icono de bloqueo de sesgo

imagen-20211213145511987.png

Icono de candado ligero

image-20211213150317351.png

  • También podemos ver en el diagrama que el bloqueo sesgado solo ocurrirá CAS una vez, mientras que el bloqueo ligero ocurrirá CAS todo el tiempo Necesitamos saber que el giro del subproceso causado por CAS también consume la programación de la CPU, porque los subprocesos están todos activos , entonces la CPU tendrá un cambio de programación de subprocesos. Por lo tanto, es divertido favorecer los bloqueos en proyectos donde la concurrencia no es muy alta ni común.
 ​
 class User{
     String userName;
 }
 public class SoftLock {
     public static void main(String[] args) throws InterruptedException {
         User user = new User();
         System.out.println("加锁前(禁用偏向延迟,此时应该是偏向锁默认):"+ClassLayout.parseInstance(user).toPrintable());
         final Thread t1 = new Thread(new Runnable() {
             @Override
             public void run() {
                 synchronized (user) {
                     System.out.println("t1加锁中:" + ClassLayout.parseInstance(user).toPrintable());
                 }
             }
         });
         t1.start();
         t1.join();
         final Thread t2 = new Thread(new Runnable() {
             @Override
             public void run() {
                 synchronized (user) {
                     System.out.println("t1加锁中,因为t1加锁后线程偏向锁不会释放,所以t2会发生偏向锁撤销,最终t2轻量级锁:" + ClassLayout.parseInstance(user).toPrintable());
                 }
             }
         });
         t2.start();
         t2.join();
         System.out.println("加锁后(无锁):"+ClassLayout.parseInstance(user).toPrintable());
     }
 }
复制代码
  • Podemos ver en el código anterior que intentar bloquear el subproceso t2 se convertirá en un bloqueo ligero. La diferencia entre un candado liviano y un candado sesgado es que el candado liviano liberará el candado después de su uso y se convertirá en un estado libre de candado.
  • Cuando el bloqueo es un bloqueo sesgado y otro subproceso accede a él, el bloqueo sesgado se actualizará a un bloqueo liviano y otros subprocesos intentarán adquirir el bloqueo en forma de giro sin bloqueo, mejorando así el rendimiento.
  • Cuando el código ingresa al bloque de sincronización, si el estado de bloqueo del objeto de sincronización es un estado sin bloqueo (el indicador de bloqueo es "01", si es un bloqueo sesgado es "0"), la máquina virtual primero establecerá un marco de pila en el subproceso actual. El espacio llamado Registro de bloqueo se utiliza para almacenar una copia de la Palabra de marca actual del objeto de bloqueo y luego copiar la Palabra de marca en el encabezado del objeto al Registro de bloqueo.
  • Después de que la copia sea exitosa, la máquina virtual usará la operación CAS para intentar actualizar la palabra de marca del objeto a un puntero al registro de bloqueo y apuntará el puntero del propietario en el registro de bloqueo a la palabra de marca del objeto.
  • Si la operación de actualización se realiza correctamente, el subproceso posee el bloqueo del objeto y el indicador de bloqueo del objeto Mark Word se establece en "00", lo que indica que el objeto se encuentra en un estado de bloqueo ligero.
  • Si la operación de actualización del bloqueo ligero falla, la máquina virtual primero verificará si la palabra de marca del objeto apunta al marco de la pila del subproceso actual. Si es así, significa que el subproceso actual ya posee el bloqueo del objeto. luego puede ingresar directamente al bloque de sincronización para continuar. Ejecutar, de lo contrario, significa que varios subprocesos compiten por el bloqueo.
  • Si actualmente solo hay un subproceso en espera, el subproceso espera girando. Pero cuando el giro excede un cierto número de veces, o un subproceso mantiene el candado, otro está girando y hay una tercera visita, el candado liviano se actualiza a un candado pesado.
  • Múltiples subprocesos solicitan el mismo bloqueo en diferentes momentos, lo que significa que no hay competencia de bloqueo. En respuesta a esta situación, la máquina virtual de Java utiliza bloqueos ligeros para evitar el bloqueo y la reactivación de bloqueos pesados.
  • La condición para un candado ligero es que se produzca una contención o que se tenga que adquirir un candado ligero. Echemos un vistazo a un caso en el que se debe aplicar un bloqueo ligero. Tenga en cuenta que el atributo VM se activa con un retraso de bloqueo sesgado y la VM no realiza ninguna configuración.
 public class SimpleTest {
     public static void main(String[] args) {
         SimpleTest test = new SimpleTest();
         System.out.println(ClassLayout.parseInstance(test).toPrintable());
         synchronized (test) {
             System.out.println(ClassLayout.parseInstance(test).toPrintable());
         }
     }
 }
复制代码
  • Este código es el mismo que el código anterior para la demostración de bloqueo sesgado bloqueo sesgado anónimo, la diferencia es que la configuración de la máquina virtual se cancela. Es decir, el retardo de bloqueo de polarización está activado. Luego, la marca en el objeto de prueba que imprimimos por primera vez es un estado sin bloqueo. Es lógico que la segunda vez sea en el bloqueo de polarización. Pero imaginemos que el sesgo de retraso también puede estar sesgado cuando el bloqueo de sesgo se aplica por segunda vez. ¿No es esto una disputa de recursos? Para evitar conflictos con el sesgo de retraso, la segunda vez es directamente ligera.

image-20211215091052543.png

Las iteraciones posteriores introdujeron bloqueos pesados.

Supongo que te gusta

Origin juejin.im/post/7079947851920310309
Recomendado
Clasificación