O que são Semaphore e CountDownLatch?
O Java fornece diversas ferramentas para controle de concorrência e sincronização de threads. Entre elas, Semaphore e CountDownLatch são duas das mais úteis quando precisamos gerenciar o acesso a recursos compartilhados ou coordenar múltiplas threads.
1. O que é Semaphore
?
O Semaphore
é usado para limitar o número de threads que podem acessar um recurso ao mesmo tempo. Funciona como um controle de acesso.
Exemplo de uso de Semaphore
import java.util.concurrent.Semaphore;
class RecursoCompartilhado {
private final Semaphore semaphore;
public RecursoCompartilhado(int limite) {
this.semaphore = new Semaphore(limite);
}
public void acessar() {
try {
semaphore.acquire(); // Adquire um acesso
System.out.println(Thread.currentThread().getName() + " acessou o recurso");
Thread.sleep(1000); // Simulando uso do recurso
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
semaphore.release(); // Libera o acesso
}
}
}
public class Main {
public static void main(String[] args) {
RecursoCompartilhado recurso = new RecursoCompartilhado(2);
for (int i = 0; i < 5; i++) {
new Thread(recurso::acessar).start();
}
}
}
Explicação:
- Apenas 2 threads podem acessar o recurso ao mesmo tempo.
- Outras threads esperam até que uma libere o acesso.
2. O que é CountDownLatch
?
O CountDownLatch
é útil quando queremos esperar múltiplas threads terminarem antes de continuar a execução.
Exemplo de uso de CountDownLatch
import java.util.concurrent.CountDownLatch;
class Tarefa implements Runnable {
private final CountDownLatch latch;
public Tarefa(CountDownLatch latch) {
this.latch = latch;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " finalizou a tarefa.");
latch.countDown(); // Reduz o contador
}
}
public class Main {
public static void main(String[] args) throws InterruptedException {
CountDownLatch latch = new CountDownLatch(3);
for (int i = 0; i < 3; i++) {
new Thread(new Tarefa(latch)).start();
}
latch.await(); // Aguarda todas as threads finalizarem
System.out.println("Todas as tarefas foram concluídas!");
}
}
Explicação:
- O
CountDownLatch
inicia com um valor 3.- Cada thread executa
latch.countDown()
, reduzindo o contador.- O
latch.await()
bloqueia a thread principal até que o contador chegue a zero.
3. Diferença entre Semaphore
e CountDownLatch
Característica | Semaphore | CountDownLatch |
---|---|---|
Reutilizável? | Sim | Não, após chegar a zero não pode ser reiniciado |
Controle de acesso | Limita número de threads acessando recurso | Aguarda múltiplas threads concluírem |
Permite múltiplas aquisições? | Sim, permite adquirir vários acessos | Não, cada thread reduz o contador em um |
Conclusão
O Semaphore
é ideal para controlar o acesso simultâneo a um recurso, enquanto o CountDownLatch
é útil para sincronizar a finalização de múltiplas tarefas antes de prosseguir a execução do programa.
Quando usar Semaphore e CountDownLatch em Java?
A concorrência é um dos desafios mais complexos no desenvolvimento de software moderno. O uso de Semaphore
e CountDownLatch
permite um controle mais refinado sobre a execução de múltiplas threads, evitando sobrecarga de recursos e garantindo que determinadas operações só sejam realizadas após todas as partes estarem prontas.
Algumas aplicações:
- Gerenciamento de acessos concorrentes a recursos limitados
- Sincronização de múltiplas threads para conclusão de tarefas
- Controle de limites de conexões simultâneas
- Sincronização de inicialização de componentes em sistemas distribuídos
Dicas para quem está começando
- Use
Semaphore
quando precisar limitar acessos simultâneos - Use
CountDownLatch
quando precisar esperar múltiplas threads finalizarem - Lembre-se que
CountDownLatch
não pode ser reutilizado - Evite deadlocks liberando corretamente os recursos adquiridos
Contribuições de Rodrigo Farias