hablar de bloqueo

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

1. Introducción

lock es una interfaz y tiene muchas implementaciones, las más comunes son bloqueos reentrantes (ReentrantLock) y bloqueos de lectura y escritura (Read, WriteLock), que se encuentran en un paquete de bloqueos de subpaquete bajo JUC. El bloqueo necesita adquirir y liberar bloqueos explícitamente. Aunque no es tan conveniente como adquirir bloqueos implícitamente, tiene funciones de sincronización tales como la operatividad de la adquisición y liberación de bloqueos, la adquisición interrumpible de bloqueos y la adquisición de bloqueos por tiempo de espera.

imagen-20220411135241875

1.1- Introducción al método

  • void lock(): adquiere el bloqueo, si el bloqueo no está disponible, el subproceso actual se bloqueará hasta que se adquiera el bloqueo;

    Esta es la forma más simple y común de adquirir un bloqueo. No libera automáticamente el bloqueo cuando ocurre una excepción como sincronizado, por lo que debe liberarse en el bloque finalmente para garantizar que el bloqueo pueda liberarse normalmente cuando ocurre una excepción. Cabe señalar que este método no se puede interrumpir, por lo que si se encuentra en una situación de interbloqueo, lock() esperará para siempre.

  • void lockInterruptably() throws InterruptedException: Adquiere un bloqueo interrumpible y regresa cuando se interrumpe o se adquiere el bloqueo.Si el bloqueo no está disponible, el subproceso actual se bloquea hasta que se adquiere o interrumpe el bloqueo;

    A diferencia de lock(), lockInterruptably() admite la interrupción mientras espera el bloqueo, o se puede decir que lockInterruptably responde al método Thread.interrupt con una prioridad más alta. Cuando lockInterruptably llama al método de interrupción mientras espera el bloqueo, lockInterruptably no lo hace En su lugar, adquirir el bloqueo genera una InterruptedException. Y lock() es la prioridad para adquirir el bloqueo antes de responder a la interrupción. Es inútil ejecutar la interrupción mientras el bloqueo está esperando. Debe esperar hasta que el bloqueo adquiera el bloqueo antes de responder a la interrupción.

  • booleano tryLock(): intenta adquirir el bloqueo y regresa inmediatamente; verdadero: adquiere el bloqueo con éxito; falso: falla al adquirir el bloqueo;

  • boolean tryLock(long time, TimeUnit unit) throws InterruptedException:尝试在指定的超时时间获取锁,当获取到锁时返回true;当超时或被中断时返回false;

  • Condition newCondition():返回一个和锁绑定的条件队列;在等待条件之前线程必须先获取当前锁,同时await()方法会原子地释放锁,并在返回之前重新获取到锁;

  • void unlock():释放锁;

ReentrantLock和ReadWriteLock是此接口的实现:

imagen-20220411140005843

2.Lock锁的意义

  1. 对比于更加古老的synchronized锁,lock锁的操作更加的灵活,Lock提供了更丰富的锁操作
  2. 通常来说锁的作用是提供多线程对共享资源的独占访问,一次只能由一个线程获得锁,只有获得锁的线程拥有对共享资源的访问权限,但是有些所可以做到对共享资源的并发访问,比如读写锁可以并发的读共享资源。

3.用法

下面的代码是一个基本的示例,声明一个Lock锁的实例对象,调用lock方法加锁,与synchronized自动解锁所不同的是Lock需要手动释放锁,正是如此是的lock锁有了很强大的灵活性。

Lock lock = new ReentrantLock();
lock.lock();
try{
  
}finally {
  lock.unlock();
}
复制代码

3.1-Condition 的用法

关键字 synchronized 与 wait()/notify()这两个方法一起使用可以实现等待/通知模式, Lock 锁的 newContition()方法返回的 Condition 对象也可以实现等待/通知模式。 用 notify()通知时,JVM 会随机唤醒某个等待的线程, 而使用 Condition 类可以进行选择性通知, Condition 比较常用的两个方法:

  • await() : El subproceso actual esperará y el bloqueo se liberará al mismo tiempo. Cuando otros subprocesos llamen signal()al método, el subproceso inactivo recuperará el bloqueo y continuará ejecutando el código (despierta donde está inactivo).
  • signal() : se usa para despertar un hilo en espera.

Cabe señalar que antes de llamar al método await()/signal() de Condition, el subproceso también debe mantener el bloqueo de bloqueo correspondiente. Después de llamar a await(), el subproceso liberará el bloqueo. En la cola de espera del objeto , se activa un subproceso, y el subproceso activado comienza a intentar adquirir el bloqueo y continúa ejecutándose una vez que el bloqueo se adquiere con éxito.

class Share {
//通过两个线程对number进行加减操作,一个线程当number == 0时 对number++,另外一个线程当number == 1时对number--
    private Integer number = 0;
​
    private ReentrantLock lock = new ReentrantLock();
​
    private Condition newCondition = lock.newCondition();
​
    // number++
    public void incr() {
        try {
            lock.lock(); // 加锁
            while (number != 0) {
                newCondition.await();//沉睡
            }
            number++;
            System.out.println(Thread.currentThread().getName() + "::" + number);
            newCondition.signal(); //唤醒另一个沉睡的线程 
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
​
    // number--
    public void decr() {
        try {
            lock.lock();
            while (number != 1) {
                newCondition.await();
            }
            number--;
            System.out.println(Thread.currentThread().getName() + "::" + number);
            newCondition.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}
​
public class LockDemo2 {
    public static void main(String[] args) {
        Share share = new Share();
​
        new Thread(()->{
            for (int i=0;i<=10;i++){
                share.incr();
            }
        },"AA").start();
​
        new Thread(()->{
            for (int i=0;i<=10;i++){
                share.decr();
            }
        },"BB").start();
        /**out:
         * AA::1
         * BB::0
         * AA::1
         * BB::0
         * .....
         */     
    }
}
复制代码

Supongo que te gusta

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