Los candados sesgados/los candados ligeros/los candados pesados son más saludables. Déjame decirte cómo se logran el bloqueo y el desbloqueo.

¡Acostúmbrate a escribir juntos! Este es el séptimo día de mi participación en el "Nuggets Daily New Plan·Desafío de actualización de abril", haz clic para ver los detalles del evento

Actualización de candado ligero Candado pesado

  • Bloqueo sesgado en JVM cuando solo un hilo lo agarra
  • Cuando aparece un hilo, es un candado ligero. Las cerraduras ligeras se bloquean a través de CAS. fallar y girar
  • Cuando el giro es grande hasta cierto punto u otro subproceso está bloqueado en este momento, cambiará a un bloqueo de peso pesado.
 ​
 class Heavy{
 ​
 }
 public class HeavyLock {
     public static void main(String[] args) throws InterruptedException {
         Heavy heavy = new Heavy();
         final Thread t1 = new Thread(new Runnable() {
             @SneakyThrows
             @Override
             public void run() {
                 synchronized (heavy) {
                     System.out.println("t1:"+ClassLayout.parseInstance(heavy).toPrintable());
                 }
                 TimeUnit.SECONDS.sleep(1000000);
             }
         });
         final Thread t2 = new Thread(new Runnable() {
             @SneakyThrows
             @Override
             public void run() {
                 synchronized (heavy) {
                     System.out.println("t2"+ClassLayout.parseInstance(heavy).toPrintable());
                 }
                 TimeUnit.SECONDS.sleep(1000000);
             }
         });
         final Thread t3 = new Thread(new Runnable() {
             @SneakyThrows
             @Override
             public void run() {
                 synchronized (heavy) {
                     System.out.println("t3"+ClassLayout.parseInstance(heavy).toPrintable());
                 }
                 TimeUnit.SECONDS.sleep(1000000);
             }
         });
 ​
         t1.start();
         TimeUnit.SECONDS.sleep(2);
         t2.start();
         t3.start();
         TimeUnit.SECONDS.sleep(5);
         System.out.println(ClassLayout.parseInstance(heavy).toPrintable());
     }
 }
复制代码
  • Podemos encontrar que cuando dos subprocesos compiten por bloqueos livianos, cambiarán a bloqueos pesados.

image-20211213165517269.png

  • Si bien todos son bloqueos pesados, descubrí que otra información está arreglada. Esto es lo mismo que nuestro diseño de memoria. Aquí, apunta al puntero de bloqueo, que corresponde al puntero de objeto ObjectMonitor en C++. Hay una cola dentro del puntero de peso pesado, que se usa para suspender el hilo que no se ha tomado. Así que no habrá ningún cambio aquí. Tenga en cuenta aquí para distinguir con la identificación del hilo
  • Después de que se agote el bloqueo de peso pesado, se liberará en un estado libre de bloqueo.

image-20211213165803310.png

operación de bloqueo

  • Arriba hemos introducido la definición de bloqueo de polarización, bloqueo ligero, bloqueo pesado y cambio de escena. Aquí resumimos brevemente los tres escenarios de uso de bloqueo

  • Los bloqueos sesgados son bloqueos sesgados de forma predeterminada cuando la JVM abre condiciones de sesgo.

  • Cuando otro subproceso vuelve a bloquear el objeto, es un bloqueo ligero independientemente de si hay competencia. Es solo que cuando ocurre una competencia, CAS se adelantará, y si CAS falla una cierta cantidad de veces, se actualizará el bloqueo de peso pesado. El proceso de cambiar el bloqueo de polarización al bloqueo ligero consiste en revocar primero el bloqueo de polarización en el bloqueo ligero.

  • Cuando haya dos o más competiciones, cambiará a un bloqueo de peso pesado. Habrá un hilo esperando girando antes de cambiar. El valor predeterminado es 10 veces. Esto no se soluciona debido a la existencia de spinlocks adaptativos.

  • Además de la relación entre bloqueos, también debemos dominar el principio de cada bloqueo, todo el proceso de bloqueo y desbloqueo.

  • Bloqueo de polarización

    bloqueado

    • Primero comprobamos si el bit de estado inferior es verdadero 101. Si está viendo si el threadId almacenado en el markword actual es el hilo actual. Si es el subproceso actual, se puede ejecutar el bloque de código actual
    • Si no es el subproceso actual, escriba en el subproceso actual a través de CAS; si la escritura es exitosa, el bloqueo de polarización se bloquea con éxito y el bloque de código actual continúa.
    • Si la escritura de CAS falla, hay preferencia de recursos. Los candados sesgados se actualizan a candados ligeros.

image-20211214094108242.png

### 解锁

-   上面的代码案列中,我也有所提到偏向锁是不会主动释放的。因为我们在还没加锁的时候默认就是偏向锁。只有发生竞争了升级轻量级锁的时候才会撤销偏向锁。
-   所以说偏向锁的解锁就是不操作。我们这里主要说下在升级轻量级锁是关于偏向锁的撤销的逻辑
复制代码

image-20211214094710414.png

## 轻量级锁

### 上锁

-   轻量级锁上锁过程需要借助一个`Lock Record` ; 他是存储在线程栈帧中的一块内存地址。
复制代码

image-20211214100148111.png

-   因为偏向锁不需要释放,他的可重入式锁就是不做任何操作。但是在轻量级锁中涉及到释放锁。那么轻量级锁如何体现可重入式呢?[这里参考下这篇文章](https://dandelioncloud.cn/article/details/1403089140002131970);
-   在上图中如果是无锁或者偏向锁会在线程栈中开辟LockRecord来存储markword的地址叫做`Displaced MardWord`
-   但是在已经是偏向锁的条件分支里,我没有体现可重入式的概念。在这条分支线里实际上是检测到markword中指向的是当前栈帧的时候JVM还是会开辟一个`Lock Record`,也不会写回到markword中。`LockRecord`不会存储原本markword的内容。此时的`LockRecord`本身就是一个计数器的功能。在释放重入式锁的时候也只是删除`LockRecord`而不会去操作markword。
-   为什么JVM这样设计呢?因为这样就避免了每次轻量级锁的开销

### 解锁

-   对于轻量级锁,其性能提升的依据是“对于绝大部分的锁,在整个生命周期内都是不会存在竞争的”,如果打破这个依据则除了互斥的开销外,还有额外的CAS操作,因此在有多线程竞争的情况下,轻量级锁比重量级锁更慢;
复制代码

image-20211214102418799.png

Resumir

  • synchronizedComo un diseño que fue criticado, realmente fue revisado después de JDK1.6.No lo mires de la misma manera que antes. Después de todo, la introducción de bloqueos sesgados y bloqueos ligeros ha mejorado mucho el rendimiento.
  • 偏向锁默认进行,节省调度时间
  • 轻量级锁通过CAS完成等待,省调线程挂起,唤醒等操作
  • 重量级将线程串行化,保障了线程之间的并发
  • 三种状态锁循序渐进给我们适配不同程度的并发需求

Supongo que te gusta

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