Ingrese AQS desde ReentrantLock

Lectura del código fuente de AQS

Hoy, a partir del método de bloqueo de ReentrantLock, profundizaremos un poco en AQS para ver cómo AQS logra el propósito de bloquear y desbloquear. Primero, pruebe qué sucede cuando solo un hilo se bloquea y luego pruebe cómo lidiar con múltiples hilos. . y, por último, observe cómo la operación de desbloqueo activa otros subprocesos.

solo un hilo

código de prueba

public class TestReentantLock {
    static ReentrantLock lock = new ReentrantLock(true);
    static Runnable r1 = ()-> {
        // 断点位置
        lock.lock();
    };
    public static void main(String[] args) {
        new Thread(r1).start();
    }
}
复制代码

Proceso de implementación

imagen-20220411194329982 imagen-20220411194455095 imagen-20220411194554405 imagen-20220411194743774 imagen-20220411195410278 imagen-20220411195543686 imagen-20220411195908861 imagen-20220411200033141

Resumir

A través de este proceso puedes obtener:

  1. Cuando solo hay un subproceso, el valor del estado se establece a través de CAS, lo que indica que el bloqueo actual está en manos de un subproceso
  2. Cuando solo hay un hilo, las operaciones de nodos y colas no están involucradas.

cuando dos hilos

código de prueba

package process;


import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

public class TestReentantLock {
    static ReentrantLock lock = new ReentrantLock(true);
    static Runnable r1 = ()-> {
        lock.lock();
        try {
            System.in.read();
        } catch (IOException e) {
            e.printStackTrace();
        }
    };
    static Runnable r2 = ()->{
        // 断点位置
        lock.lock();
    };

    public static void main(String[] args) throws InterruptedException {
        new Thread(r1).start();
        TimeUnit.SECONDS.sleep(1);
        new Thread(r2).start();
    }
}
复制代码

Proceso de implementación

imagen-20220411200636003 imagen-20220411200757320 imagen-20220411201532550 imagen-20220411201712606 imagen-20220411201851645 imagen-20220411202300875 image-20220411202515374 image-20220411202838888 image-20220411203147087 image-20220411203236845

Resumir

  1. Cuando hay dos subprocesos, use LockSupport.park() para suspender el subproceso para lograr el propósito de no adquirir el bloqueo
  2. Al establecer el valor waitStatus del nodo anterior en Node.Signal en -1, significa despertar el nodo posterior, es decir, a sí mismo.

operación de desbloqueo ()

código de prueba

package process;

import java.io.IOException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

public class TestReentantLock {
    static ReentrantLock lock = new ReentrantLock(true);
    static Runnable r1 = ()-> {
        lock.lock();
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 断点处
        lock.unlock();
    };
    static Runnable r2 = ()->{
        lock.lock();
    };

    public static void main(String[] args) throws InterruptedException {
        new Thread(r1).start();
        TimeUnit.MILLISECONDS.sleep(500);
        new Thread(r2).start();
    }
}

复制代码

Proceso de implementación

image-20220411204404870 image-20220411204504407 image-20220411204807717 image-20220411204944492 image-20220411205139959

Resumir

  1. Obtenga el nodo principal y use el estado de espera del nodo principal para determinar el desbloqueo de subprocesos posteriores

Resumir

La forma en que AQS logra la sincronización de subprocesos se puede resumir de la siguiente manera:

  1. Bloquee el hilo a través de LockSupport.park() para lograr el propósito de no poder adquirir el bloqueo
  2. Actualice atómicamente la cabeza y la cola de la cola a través de CAS
  3. A través de un estado volátil se logra el propósito de identificar el estado de la cerradura

Supongo que te gusta

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