0Pricing
Java Academy · Aula

ReentrantLock versus synchronized

Compare os recursos de ReentrantLock (tryLock, lockInterruptibly e imparcialidade) com a palavra-chave synchronized.

ReentrantLock versus synchronized é uma aula grátis de Java Academy no CoddyKit. Esta é a aula 1 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Java Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Java Academy inclui 4 aulas no total.

A palavra-chave synchronized

A palavra-chave synchronized do Java fornece exclusão mútua usando o bloqueio intrínseco do objeto (monitor). É simples, mas limitada — não oferece tempo limite, equidade nem capacidade de interrupção.

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()

Noções básicas de ReentrantLock

ReentrantLock é um bloqueio explícito de java.util.concurrent.locks. Ele fornece a mesma exclusão mútua que synchronized, mas com mais controle. O bloqueio deve ser liberado manualmente em um bloco 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: aquisição sem bloqueio

tryLock() tenta adquirir o bloqueio sem bloquear. Retorna true se for bem-sucedido e false se o bloqueio estiver mantido por outra linha de execução.

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 com tempo limite

Aguarde até um tempo especificado para adquirir o bloqueio:

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() adquire o bloqueio, a menos que a linha de execução seja interrompida — é útil para tarefas canceláveis que aguardam um bloqueio:

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();
}

Reentrância

Tanto synchronized quanto ReentrantLock são reentrantes — uma linha de execução que já mantém o bloqueio pode adquiri-lo novamente sem causar um deadlock:

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 equidade

Crie um ReentrantLock justo para conceder acesso na ordem FIFO — isso evita a inanição de linhas de execução, mas reduz o throughput:

// 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

Variáveis de condição

ReentrantLock fornece objetos Condition — mais flexíveis 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(); }

Quando usar ReentrantLock em vez de synchronized

Use synchronized quando:

  • For necessária uma exclusão mútua simples
  • Não forem necessários tempo limite, equidade nem capacidade de interrupção

Use ReentrantLock quando:

  • For necessário tryLock() ou tryLock com tempo limite
  • For necessário lockInterruptibly()
  • For necessária uma ordenação justa
  • Forem necessárias várias variáveis de condição

Contagem e monitoramento do bloqueio

ReentrantLock fornece 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

Erro comum: desbloquear sem bloquear

Chamar unlock() quando a linha de execução atual não mantém o bloqueio lança IllegalMonitorStateException. Sempre associe lock a unlock ou 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!");
}

Verificação rápida

Qual método de ReentrantLock permite que uma linha de execução adquira o bloqueio ou retorne imediatamente, sem bloquear, se o bloqueio não estiver disponível?

Recapitulação: ReentrantLock vs synchronized

Principais conclusões:

  • Ambos fornecem exclusão mútua e reentrância
  • ReentrantLock acrescenta: tryLock, lockInterruptibly, equidade e condições
  • Sempre libere o bloqueio em um bloco finally
  • synchronized é mais simples — prefira-o quando seus recursos forem suficientes
  • Use ReentrantLock em cenários avançados: tempos limite, capacidade de interrupção e várias condições

Perguntas Frequentes

A aula “ReentrantLock versus synchronized” é grátis?

Sim — o texto completo de “ReentrantLock versus synchronized” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Java Academy, atualize para CoddyKit PRO. O curso de Java Academy inclui 4 aulas no total.

O que vou aprender em “ReentrantLock versus synchronized”?

Compare os recursos de ReentrantLock (tryLock, lockInterruptibly e imparcialidade) com a palavra-chave synchronized. Você pratica Java Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar Java Academy?

Nenhuma experiência prévia é necessária. Java Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 1 de 4.

Quanto tempo leva a aula “ReentrantLock versus synchronized”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de Java Academy?

Sim. Cada aula de Java Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. ReentrantLock versus synchronized
  2. ReadWriteLock em Cenários de Leitura e Escrita
  3. Variáveis Atômicas: Atualizações sem Bloqueios
  4. StampedLock e Leituras Otimistas
← Voltar para Java Academy