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
javaclass 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
javaimport 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
Teste seu Conhecimento
Teste sua compreensão deste tópico com questões práticas.
📝 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