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 releasedPolí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()); // trueVariá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 releasedErro 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
- ReentrantLock versus synchronized
- ReadWriteLock em Cenários de Leitura e Escrita
- Variáveis Atômicas: Atualizações sem Bloqueios
- StampedLock e Leituras Otimistas