Como utilizar ReentrantLock para sincronização de threads?
O ReentrantLock
é uma alternativa ao uso do synchronized
em Java, oferecendo maior flexibilidade e controle sobre a sincronização de threads.
1. O que é ReentrantLock
?
O ReentrantLock
faz parte do pacote java.util.concurrent.locks
e permite que uma thread bloqueie e desbloqueie recursos manualmente, garantindo que apenas uma thread por vez acesse um determinado código.
2. Exemplo de uso básico
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class Contador {
private int valor = 0;
private final Lock lock = new ReentrantLock();
public void incrementar() {
lock.lock();
try {
valor++;
} finally {
lock.unlock();
}
}
public int getValor() {
return valor;
}
}
Explicação:
lock.lock()
bloqueia o acesso ao código para outras threads.finally { lock.unlock(); }
garante que o bloqueio seja liberado corretamente.
3. Diferença entre synchronized
e ReentrantLock
Característica | synchronized |
ReentrantLock |
---|---|---|
Liberação automática | Sim, quando o método termina | Não, deve ser liberado manualmente |
Tentativa de bloqueio sem espera | Não | Sim, com tryLock() |
Interrupção de thread bloqueada | Não | Sim |
4. Tentando obter um bloqueio sem esperar
Podemos usar tryLock()
para tentar adquirir o bloqueio sem aguardar indefinidamente:
if (lock.tryLock()) {
try {
// Código protegido pelo bloqueio
} finally {
lock.unlock();
}
} else {
System.out.println("Outra thread já está executando esta operação.");
}
5. Fazendo bloqueios com tempo limite
Para evitar deadlocks, podemos definir um tempo máximo para aguardar o bloqueio:
try {
if (lock.tryLock(2, TimeUnit.SECONDS)) {
try {
// Código crítico
} finally {
lock.unlock();
}
} else {
System.out.println("Não foi possível obter o bloqueio dentro do tempo limite.");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
Conclusão
O ReentrantLock
oferece mais controle sobre a sincronização de threads do que synchronized
, sendo útil em situações onde é necessário tempo de espera limitado, interrupção de threads bloqueadas ou tentativa de bloqueio sem espera.
Quando usar ReentrantLock ao invés de synchronized?
Em sistemas multithread, a escolha entre synchronized
e ReentrantLock
pode impactar diretamente o desempenho da aplicação. O synchronized
é mais simples e confiável para bloqueios básicos, enquanto o ReentrantLock
permite um controle refinado, evitando situações como deadlocks e esperas indefinidas.
Algumas aplicações:
- Evitar race conditions em sistemas concorrentes
- Garantir exclusão mútua ao acessar recursos compartilhados
- Gerenciar melhor o tempo de espera de threads bloqueadas
- Evitar deadlocks em sistemas complexos
Dicas para quem está começando
- Sempre chame
lock.unlock()
dentro de umfinally
- Use
tryLock()
para evitar esperas indefinidas - Evite bloquear recursos por mais tempo do que o necessário
- Prefira
synchronized
para casos simples eReentrantLock
para maior controle
Contribuições de Rodrigo Farias