Implementando sincronização de threads em Java com CyclicBarrier

Por Gaspar Barancelli Junior em 12 de maio de 2024
Imagem ilustrativa sobre o post Implementando sincronização de threads em Java com CyclicBarrier

No mundo do desenvolvimento de software, especialmente em ambientes multithread, sincronizar tarefas é uma necessidade comum e crítica. Java, com sua rica API de concorrência, oferece várias ferramentas para lidar com esses desafios, sendo uma delas a CyclicBarrier. Neste post, exploraremos o que é a CyclicBarrier, como ela funciona e como pode ser aplicada em seus projetos Java.

O que é CyclicBarrier?

A CyclicBarrier é uma barreira de sincronização que permite que múltiplas threads esperem umas pelas outras para alcançar um ponto comum antes de continuar com a execução. Isso é particularmente útil em programas que envolvem uma série de passos ou fases onde múltiplas threads devem completar cada fase antes de prosseguir para a próxima.

Como a CyclicBarrier funciona

A CyclicBarrier funciona sob o princípio de que um número específico de threads deve "esperar" em um ponto de barreira. Quando a última thread chega à barreira, (ou seja, todas as threads necessárias chegaram), opcionalmente, uma tarefa pode ser executada. Essa tarefa é definida como uma ação de barreira, e é uma funcionalidade ideal para a execução de procedimentos de limpeza ou atualização de estado antes de seguir para a próxima etapa.

Exemplo

Sincronizando Etapas de Processamento

Vamos ver um exemplo simples de como usar a CyclicBarrier. Imagine um cenário onde três threads estão trabalhando juntas para processar dados em três etapas:

import java.util.concurrent.CyclicBarrier;

public class ProcessadorDeDados implements Runnable {
    private final CyclicBarrier barreira;

    public ProcessadorDeDados(CyclicBarrier barreira) {
        this.barreira = barreira;
    }

    @Override
    public void run() {
        try {
            System.out.println("Processando fase 1");
            barreira.await();

            System.out.println("Processando fase 2");
            barreira.await();

            System.out.println("Processando fase 3");
            barreira.await();

            System.out.println("Processamento completo por " + Thread.currentThread().getName());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        int numeroDeThreads = 3;
        CyclicBarrier barreira = new CyclicBarrier(numeroDeThreads, () -> System.out.println("Todas as fases estão completas"));

        for (int i = 0; i < numeroDeThreads; i++) {
            new Thread(new ProcessadorDeDados(barreira), "Thread-" + i).start();
        }
    }
}

No código acima, três threads são criadas e cada uma delas executa o mesmo código, que consiste em processar três fases. A CyclicBarrier é usada para garantir que todas as threads completem cada fase antes de qualquer uma delas iniciar a próxima. A mensagem "Todas as fases estão completas" é impressa uma vez que todas as threads alcançam a barreira após a terceira fase.

Processando fase 1
Processando fase 1
Processando fase 1
Todas as fases estão completas
Processando fase 2
Processando fase 2
Processando fase 2
Todas as fases estão completas
Processando fase 3
Processando fase 3
Processando fase 3
Todas as fases estão completas
Processamento completo por Thread-1
Processamento completo por Thread-0
Processamento completo por Thread-2
Simulação de uma corrida

A CyclicBarrier também pode ser usada para simular situações do mundo real, como uma corrida onde os participantes precisam esperar que todos estejam prontos antes de começar:

import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.BrokenBarrierException;

public class Corrida {
    public static void main(String[] args) {
        final int NUMERO_DE_CORREDORES = 5;
        CyclicBarrier barreira = new CyclicBarrier(NUMERO_DE_CORREDORES, () -> System.out.println("Todos os corredores estão prontos. Vamos começar a corrida!"));

        for (int i = 1; i <= NUMERO_DE_CORREDORES; i++) {
            int corredorId = i;
            new Thread(() -> {
                System.out.println("Corredor " + corredorId + " está pronto.");
                try {
                    barreira.await();
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

Conclusão

A CyclicBarrier é essencial para qualquer desenvolvedor Java que trabalhe com programação concorrente. Ela oferece uma maneira eficaz de sincronizar threads em pontos críticos de execução, o que é crucial para o processamento de tarefas complexas e para a realização de simulações detalhadas. Entender e utilizar corretamente a CyclicBarrier pode significativamente melhorar a robustez e a eficiência de suas aplicações multi-thread.

// Compartilhe esse Post

💫
🔥 NOVO APP

Domine o Inglês em 30 dias!

Inteligência Artificial + Repetição Espaçada • Método cientificamente comprovado

✅ Grátis para começar 🚀 Resultados rápidos
×