Carregando...

Multithreading e Concorrência

Multithreading e concorrência são conceitos fundamentais no desenvolvimento de software moderno e na arquitetura de sistemas escaláveis. Multithreading refere-se à execução simultânea de múltiplos threads dentro de um mesmo processo, permitindo que tarefas independentes sejam executadas de forma paralela. Concorrência, por outro lado, envolve a gestão segura e eficiente desses threads, garantindo que recursos compartilhados sejam acessados sem conflitos e que o desempenho do sistema seja otimizado.
Esses conceitos são essenciais em sistemas de alta performance, aplicações em tempo real, servidores web de grande escala e microserviços distribuídos. O entendimento de multithreading e concorrência inclui domínio de sintaxe Java, estruturas de dados thread-safe, algoritmos de sincronização e princípios de programação orientada a objetos (OOP) para manter o código modular e reutilizável.
Ao final deste tutorial, o leitor aprenderá a criar e gerenciar threads, sincronizar recursos compartilhados, utilizar pools de threads com ExecutorService, prevenir deadlocks e aplicar padrões de concorrência em aplicações reais. Também será abordada a identificação de problemas comuns, como condições de corrida (race conditions), vazamentos de memória e erros de concorrência, permitindo a criação de sistemas confiáveis e de alto desempenho.

Exemplo Básico

java
JAVA Code
class Contador {
private int count = 0;

public synchronized void incrementar() {
count++;
}

public int getValor() {
return count;
}

}

class ThreadContador extends Thread {
private Contador contador;

public ThreadContador(Contador contador) {
this.contador = contador;
}

@Override
public void run() {
for (int i = 0; i < 1000; i++) {
contador.incrementar();
}
}

}

public class Main {
public static void main(String\[] args) throws InterruptedException {
Contador contador = new Contador();
Thread t1 = new ThreadContador(contador);
Thread t2 = new ThreadContador(contador);

t1.start();
t2.start();

t1.join();
t2.join();

System.out.println("Valor final: " + contador.getValor());
}

}

Neste exemplo básico, demonstramos multithreading com um contador compartilhado. A classe Contador encapsula o recurso compartilhado count e utiliza o método incrementar sincronizado para garantir que apenas um thread por vez modifique o valor. A classe ThreadContador estende Thread e incrementa o contador 1000 vezes, simulando uma carga concorrente real.
No método main, dois threads são inicializados sobre a mesma instância de Contador. A chamada join() garante que o thread principal espere até que ambos os threads terminem a execução, garantindo um valor final correto. Esse padrão de separação de responsabilidades entre lógica de contagem e execução concorrente exemplifica boas práticas de OOP e é aplicável em situações como contagem de visitantes, processamento de logs ou gerenciamento de transações simultâneas.

Exemplo Prático

java
JAVA Code
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

class ContaBancaria {
private double saldo;
private Lock lock = new ReentrantLock();

public void depositar(double valor) {
lock.lock();
try {
saldo += valor;
} finally {
lock.unlock();
}
}

public void sacar(double valor) {
lock.lock();
try {
if (saldo >= valor) {
saldo -= valor;
}
} finally {
lock.unlock();
}
}

public double getSaldo() {
return saldo;
}

}

public class SimuladorBancario {
public static void main(String\[] args) throws InterruptedException {
ContaBancaria conta = new ContaBancaria();
ExecutorService executor = Executors.newFixedThreadPool(5);

for (int i = 0; i < 10; i++) {
executor.execute(() -> conta.depositar(100));
executor.execute(() -> conta.sacar(50));
}

executor.shutdown();
while (!executor.isTerminated()) {
}

System.out.println("Saldo final: " + conta.getSaldo());
}

}

Neste exemplo avançado, utilizamos ReentrantLock para controlar o acesso ao saldo de uma conta bancária de forma segura, mostrando como substituir synchronized por uma solução mais flexível. O ExecutorService gerencia um pool de threads, melhorando o desempenho e evitando a criação excessiva de threads. A classe ContaBancaria encapsula a lógica de depósito e saque, respeitando princípios de OOP e separação de responsabilidades.
Este padrão é aplicável a sistemas financeiros, controle de estoque ou processamento de dados com alta concorrência. O uso correto de locks evita condições de corrida e deadlocks, enquanto a utilização de pools de threads reduz a sobrecarga e aumenta a escalabilidade.

As melhores práticas incluem: proteger recursos compartilhados com locks ou métodos sincronizados, utilizar pools de threads, liberar locks em blocos finally, minimizar blocos críticos e prevenir deadlocks. Erros comuns envolvem gerenciamento inadequado de locks, exceções não tratadas que interrompem threads e operações longas dentro de blocos sincronizados.
Para depuração, é recomendado logar atividades de threads e usar ferramentas de concorrência do Java. Para otimização, reduzir o contention, utilizar estruturas de dados thread-safe como ConcurrentHashMap e manter operações críticas pequenas. Considerações de segurança incluem proteção de dados sensíveis e acesso controlado a recursos compartilhados.

📊 Tabela de Referência

Element/Concept Description Usage Example
Thread Unidade básica de execução Java Thread t = new Thread(runnable)
Runnable Interface para definir tarefas class MinhaTarefa implements Runnable
synchronized Sincroniza acesso a métodos ou blocos public synchronized void incrementar()
Lock Mecanismo flexível de sincronização lock.lock()/lock.unlock()
ExecutorService Gerencia pools de threads Executors.newFixedThreadPool(5)

Aprender Multithreading e Concorrência permite criar, gerenciar e sincronizar threads de forma eficiente, essencial para sistemas backend de alta performance, microserviços, processamento em tempo real e aplicações distribuídas. Próximos tópicos recomendados incluem Parallel Streams, Fork/Join Framework e CompletableFuture. Recomenda-se iniciar com threads simples, evoluindo para pools e sincronização avançada em cenários reais. Recursos adicionais incluem documentação Java Concurrency, livros avançados sobre concorrência e projetos open-source multithreaded.

🧠 Teste Seu Conhecimento

Pronto para Começar

Teste seu Conhecimento

Teste sua compreensão deste tópico com questões práticas.

4
Perguntas
🎯
70%
Para Passar
♾️
Tempo
🔄
Tentativas

📝 Instruções

  • Leia cada pergunta cuidadosamente
  • Selecione a melhor resposta para cada pergunta
  • Você pode refazer o quiz quantas vezes quiser
  • Seu progresso será mostrado no topo