Comprensión profunda de la explicación detallada de ReentrantReadWriteLock de AQS

Tabla de contenido

1. Introducción a ReentrantReadWriteLock

1.1 Leer, leer y escribir, escribir y leer, escribir y escribir en la práctica

1.2 Solución de problemas de seguridad de subprocesos de Hashmap en combate real

1.3 Bloquear la degradación en la práctica

2. Análisis de código fuente ReentrantReadWriteLock (TODO)

3. bloqueo estampado (TODO)


1. Introducción a ReentrantReadWriteLock

Escenario de aplicación: no hay problema de simultaneidad en las operaciones de lectura y lectura, lectura y escritura, escritura y escritura, se requiere exclusión mutua en los escenarios de lectura y escritura, y se requiere un bloqueo para bloquear los recursos necesarios.

Para el escenario anterior, java implementa reentranteReadWriteLock e implementa la degradación de bloqueo (bloqueo de escritura para bloqueo de lectura) en java, selección justa e injusta y reentrante.

Diseñe cómo implementar un bloqueo : herede AQS, implemente los métodos abstractos tryRelease y tryAcquire, y otros métodos pueden usar AQS ya encapsulado.

Horario: sincronizado

AQS: cas+cola síncrona (obteniendo bloqueo de falla de bloqueo)

Cómo diseñar un bloqueo de lectura-escritura: diseño de bloqueo de lectura-lectura, lectura-escritura, escritura-lectura, escritura-escritura

Bloqueo de lectura: bloqueo compartido

Bloqueo de escritura: bloqueo exclusivo

En AQS, 0->1 en el estado indica que se ha adquirido el bloqueo. En el bloqueo de lectura-escritura, los 32 bits modificados por int se pueden dividir. Los 16 bits superiores indican el bloqueo de lectura y los 16 bits inferiores indican el bloqueo de escritura.

Cómo juzgar el bloqueo de lectura y el bloqueo de escritura: los 16 bits superiores no son 0 o los 16 bits inferiores no son 0

1.1 Leer, leer y escribir, escribir y leer, escribir y escribir en la práctica

Excepto lectura y lectura, que no son mutuamente excluyentes, los otros tres son mutuamente excluyentes. Solo cuando se libera el primer bloqueo, se puede adquirir el siguiente bloqueo. El código de demostración es el siguiente.

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadWriteLockTest {


    //定义一个读写锁,并且定义一个读锁,一个写锁
    private ReadWriteLock lock = new ReentrantReadWriteLock();

    private Lock r = lock.readLock();
    private Lock w = lock.writeLock();

    //定义一个对象
    private Object data = "";

    //定义一个读方法
    public void read() {
        System.out.println(Thread.currentThread().getName()+"读锁-begin");
        r.lock();
        try {
            System.out.println(Thread.currentThread().getName()+"获取读锁");
            data = "read";
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            r.unlock();
            System.out.println(Thread.currentThread().getName()+"读锁-解锁");
        }
    }

    //定义一个写方法
    public void write() {
        System.out.println(Thread.currentThread().getName()+"写锁-begin");
        w.lock();
        try {
            System.out.println(Thread.currentThread().getName()+"获取写锁");
            data = "write";
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            w.unlock();
            System.out.println(Thread.currentThread().getName()+"写锁-解锁");
        }
    }

    public static void main(String[] args) {
        //测试读读,读写,写读,写写场景
        ReadWriteLockTest readWriteLockTest = new ReadWriteLockTest();
        new Thread(()->{
//            readWriteLockTest.read();
            readWriteLockTest.write();
        }).start();

        new Thread(()->{
            readWriteLockTest.read();
//            readWriteLockTest.write();
        }).start();
    }
}

1.2 Solución de problemas de seguridad de subprocesos de Hashmap en combate real

El uso de ReadWriteLock para encapsular hashMap nuevamente puede lograr problemas de seguridad de acceso simultáneos. Este escenario es adecuado para leer más y escribir menos.

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadWriteLockTest2 {

    //定义一个hashMap和读写锁
    private static Map<String,Object> map = new HashMap<String,Object>();

    private static ReadWriteLock lock = new ReentrantReadWriteLock();

    private static Lock r = lock.readLock();
    private static Lock w = lock.writeLock();

    //获取时获取读锁
    public static Object get(String key){
        try{
            r.lock();
            return map.get(key);
        }finally {
            r.unlock();
        }
    }

    //插入时插入写锁
    public static void put(String key,Object value){
        try{
            w.lock();
            map.put(key,value);
        }finally {
            w.unlock();
        }
    }

    //清理写锁
    public void clear(){
        try{
            w.lock();
            map.clear();
        }finally {
            w.unlock();
        }
    }

    public static void main(String[] args) {
        ReadWriteLockTest2.put("key","value");
        System.out.println(ReadWriteLockTest2.get("key"));
    }
}

1.3 Bloquear la degradación en la práctica

Proceso de degradación de bloqueo: los bloqueos de escritura se convierten en bloqueos de lectura.Durante el proceso de degradación de bloqueo, los bloqueos de lectura se adquieren principalmente para garantizar la visibilidad.

El escenario de la aplicación es desconocido

public class ReadWriteLockTest3 {

    private static ReadWriteLock lock = new ReentrantReadWriteLock();

    private static Lock r = lock.readLock();
    private static Lock w = lock.writeLock();

    private static boolean flag = false;

    //锁降级过程:写锁降级为读锁,1.加读锁释放读锁 2.获取写锁中间加写锁释放写锁 3.try-finally释放读锁
    public static void update(){
        r.lock();
        if(!flag){
            r.unlock();
            w.lock();//锁降级过程从此时开始
            try{
                if(!flag){
                    flag = true;
                }
                r.lock();
            }finally {
                w.unlock();//锁降级完成,写锁转为读锁
            }
        }
        try{
            //锁降级完成,写锁降为读锁
        }finally {
            r.unlock();
        }
    }
}

2. Análisis de código fuente ReentrantReadWriteLock (TODO)

HoldCounter y ThreadLocalHoldCounter en ReentrantReadWriteLock son un contador. Utilice estas dos interfaces para almacenar el número de bloqueos de lectura adquiridos. El número de reentrantes existe en ThreadLocal

punto de enfoque:

1. ¿Cómo almacena el estado el estado de los bloqueos de lectura y escritura?

        Bloqueo compartido: el valor int se desplaza a la derecha 16 bits (2 >>> 16)

        Bloqueo exclusivo: operación de bit (int c & 65536)

2. Leer bloquear y desbloquear

        El bloqueo se puede dividir aproximadamente en:

                1. Intente adquirir el bloqueo y juzgue que es un bloqueo de escritura, devuelva -1, lea el contador de bloqueo HoldCounter+1

                2. Ingrese a la operación de cola, cree una cola, falle al adquirir un bloqueo e ingrese a la cola de bloqueo síncrono de cola

        Desbloquear: obtenga el valor de estado de bloqueo para juzgar el contador usando la operación CAS -- operación

3. Escritura de bloqueo y desbloqueo (TODO)

 

 

3. bloqueo estampado (TODO)

Supongo que te gusta

Origin blog.csdn.net/qq_21575929/article/details/124719182
Recomendado
Clasificación