0Pricing
Java Academy · Lección

ReentrantLock frente a synchronized

Compare las características de ReentrantLock (tryLock, lockInterruptibly y fairness) con la palabra clave synchronized.

ReentrantLock frente a synchronized es una lección gratuita de Java Academy en CoddyKit. Esta es la lección 1 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Java Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Java Academy incluye 4 lecciones en total.

La palabra clave synchronized

La palabra clave synchronized de Java proporciona exclusión mutua mediante el bloqueo intrínseco del objeto (monitor). Es sencilla, pero limitada: no ofrece tiempo de espera, equidad ni posibilidad de interrupción.

class Counter {
    private int count = 0;
    
    synchronized void increment() {
        count++; // only one thread at a time
    }
    
    synchronized int get() { return count; }
}

Counter c = new Counter();
// Multiple threads can safely call increment()

Fundamentos de ReentrantLock

ReentrantLock es un bloqueo explícito de java.util.concurrent.locks. Proporciona la misma exclusión mutua que synchronized, pero con mayor control. El bloqueo debe liberarse manualmente en un bloque finally.

import java.util.concurrent.locks.*;

class SafeCounter {
    private int count = 0;
    private final ReentrantLock lock = new ReentrantLock();
    
    void increment() {
        lock.lock();
        try {
            count++;
        } finally {
            lock.unlock(); // always release in finally!
        }
    }
    
    int get() {
        lock.lock();
        try { return count; }
        finally { lock.unlock(); }
    }
}

tryLock: adquisición no bloqueante

tryLock() intenta adquirir el bloqueo sin bloquearse. Devuelve true si lo consigue y false si el bloqueo pertenece a otro subproceso.

ReentrantLock lock = new ReentrantLock();

if (lock.tryLock()) {
    try {
        System.out.println("Got the lock, doing work");
    } finally {
        lock.unlock();
    }
} else {
    System.out.println("Lock busy, skipping or retrying");
}

tryLock con tiempo de espera

Espere hasta un tiempo especificado para adquirir el bloqueo:

try {
    if (lock.tryLock(500, TimeUnit.MILLISECONDS)) {
        try {
            // work with protected resource
            System.out.println("Acquired within 500ms");
        } finally {
            lock.unlock();
        }
    } else {
        System.out.println("Timed out waiting for lock");
    }
} catch (InterruptedException e) {
    Thread.currentThread().interrupt();
}

lockInterruptibly

lockInterruptibly() adquiere el bloqueo a menos que se interrumpa el subproceso; resulta útil para tareas cancelables que esperan un bloqueo:

try {
    lock.lockInterruptibly(); // throws InterruptedException if interrupted
    try {
        // do work
    } finally {
        lock.unlock();
    }
} catch (InterruptedException e) {
    System.out.println("Interrupted while waiting for lock");
    Thread.currentThread().interrupt();
}

Reentrada

Tanto synchronized como ReentrantLock permiten la reentrada: un subproceso que ya posee el bloqueo puede adquirirlo de nuevo sin provocar un interbloqueo:

synchronized void outer() {
    System.out.println("outer");
    inner(); // same thread re-enters — OK
}

synchronized void inner() {
    System.out.println("inner"); // same lock, same thread
}

// ReentrantLock:
ReentrantLock lock = new ReentrantLock();
lock.lock();
lock.lock(); // acquire again — hold count = 2
lock.unlock(); // hold count = 1
lock.unlock(); // hold count = 0, lock released

Política de equidad

Cree un ReentrantLock equitativo para conceder el acceso en orden FIFO; así evita que los subprocesos sufran inanición, aunque con un menor rendimiento:

// Unfair (default): no ordering guarantee, better throughput
ReentrantLock unfair = new ReentrantLock();

// Fair: threads acquire in arrival order
ReentrantLock fair = new ReentrantLock(true);

System.out.println(fair.isFair()); // true

Variables de condición

ReentrantLock proporciona objetos Condition, más flexibles que wait()/notify():

ReentrantLock lock2 = new ReentrantLock();
Condition notEmpty = lock2.newCondition();
Queue<String> queue = new LinkedList<>();

// Producer
lock2.lock();
try {
    queue.offer("item");
    notEmpty.signal(); // wake one waiting thread
} finally { lock2.unlock(); }

// Consumer
lock2.lock();
try {
    while (queue.isEmpty()) notEmpty.await(); // wait & release lock
    System.out.println(queue.poll());
} finally { lock2.unlock(); }

Cuándo usar ReentrantLock frente a synchronized

Use synchronized cuando:

  • Se necesite una exclusión mutua sencilla
  • No se requieran tiempo de espera, equidad ni posibilidad de interrupción

Use ReentrantLock cuando:

  • Se necesite tryLock() o tryLock(timeout)
  • Se necesite lockInterruptibly()
  • Se requiera un orden equitativo
  • Se necesiten varias variables Condition

Recuento y supervisión de bloqueos

ReentrantLock proporciona métodos de diagnóstico:

ReentrantLock lock3 = new ReentrantLock();
lock3.lock();
lock3.lock(); // reentrant — hold count 2

System.out.println(lock3.getHoldCount());    // 2
System.out.println(lock3.isHeldByCurrentThread()); // true
System.out.println(lock3.isLocked());        // true
System.out.println(lock3.getQueueLength());  // 0 (no waiting threads)

lock3.unlock();
lock3.unlock(); // fully released

Error común: desbloquear sin haber bloqueado

Llamar a unlock() cuando el subproceso actual no posee el bloqueo lanza IllegalMonitorStateException. Empareje siempre lock/unlock o use try-finally:

ReentrantLock lock4 = new ReentrantLock();
try {
    // If lock() is never called (e.g., skipped by exception before this line)
    lock4.unlock(); // throws IllegalMonitorStateException
} catch (IllegalMonitorStateException e) {
    System.out.println("Must lock before unlock!");
}

Comprobación rápida

¿Qué método de ReentrantLock permite que un subproceso adquiera el bloqueo o regrese inmediatamente sin bloquearse si el bloqueo no está disponible?

Resumen: ReentrantLock frente a synchronized

Conceptos clave:

  • Ambos proporcionan exclusión mutua y reentrada
  • ReentrantLock añade: tryLock, lockInterruptibly, equidad y Conditions
  • Libere siempre el bloqueo en un bloque finally
  • synchronized es más sencillo; prefiéralo cuando sus funciones sean suficientes
  • Use ReentrantLock en situaciones avanzadas: tiempos de espera, posibilidad de interrupción y varias condiciones

Preguntas frecuentes

¿La lección «ReentrantLock frente a synchronized» es gratis?

Sí — el texto completo de «ReentrantLock frente a synchronized» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Java Academy, actualiza a CoddyKit PRO. El curso de Java Academy incluye 4 lecciones en total.

¿Qué aprenderé en «ReentrantLock frente a synchronized»?

Compare las características de ReentrantLock (tryLock, lockInterruptibly y fairness) con la palabra clave synchronized. Practicas Java Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar Java Academy?

No se requiere experiencia previa. Java Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 1 de 4.

¿Cuánto tiempo toma la lección «ReentrantLock frente a synchronized»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de Java Academy?

Sí. Cada lección de Java Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. ReentrantLock frente a synchronized
  2. ReadWriteLock para escenarios de lectores y escritores
  3. Variables atómicas: actualizaciones sin bloqueo
  4. StampedLock y lecturas optimistas
← Volver a Java Academy