O que são Semaphore e CountDownLatch?

Semaphore e CountDownLatch são mecanismos de sincronização que ajudam a controlar o acesso de múltiplas threads a recursos compartilhados.

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.

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

Compartilhe este tutorial: O que são Semaphore e CountDownLatch

Compartilhe este tutorial

Continue aprendendo:

Como utilizar ReentrantLock para sincronização de threads

ReentrantLock é uma alternativa ao synchronized, oferecendo mais controle sobre o bloqueio de threads em Java.

Tutorial anterior

Como interromper uma thread corretamente

A interrupção de threads em Java deve ser feita de forma segura para evitar deadlocks e garantir que os recursos sejam liberados corretamente.

Próximo tutorial