Java Multithreading e Concorrência em Aplicações Backend

Ciclo de Vida de Threads

Threads possuem cinco estados: criação, pronto, execução, bloqueado e encerrado. Na criação, o objeto thread é instanciado. No estado pronto, após start(), aguarda alocação de CPU. Execução ocorre quando a thread obtém recursos CPU. Bloqueio acontece quando libera CPU voluntariamente (wait, sleep, I/O), e encerramento ao finalizar run() ou por exceção.

Diferenças Entre sleep(), wait(), join() e yield()

sleep(): Pausa temporária sem liberar bloqueios. wait(): Libera recursos e bloqueios, exigindo notify()/notifyAll() para retorno. join(): Bloqueia a thread chamante até a finalização da thread alvo. yield(): Transfere voluntariamente controle para outras threads no estado pronto.

public class ExemploJoin {
    public static void main(String[] args) throws InterruptedException {
        Thread tarefa = new Thread(() -> {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Processo secundário concluído");
        });
        tarefa.start();
        tarefa.join();
        System.out.println("Processo principal finalizado");
    }
}

Segurança em Threads

Refere-se à garantia de comportamento correto durante acesso concorrente a dados compartilhados na memória heap. Requer sincronização para evitar condições de corrida e inconsistências.

Thread vs Runnable

Ambos executam tarefas concorrentes, mas Runnable favorece composição sobre herança. Thread cria instâncias independentes, enquanto Runnable permite compartilhamento de estado entre threads.

// Implementação Runnable
public class TarefaCompartilhada implements Runnable {
    private int contador = 3;
    public void run() {
        while (contador > 0) {
            System.out.println("Valor: " + contador--);
        }
    }
}

Threads Daemon

Executam em segundo plano para serviços auxiliares (ex: garbage collection). Terminam automaticamente quando todas as threads não-daemon finalizam.

ThreadLocal: Princípio e Uso

Armazena dados isolados por thread via mapa interno (ThreadLocalMap). Aplicações típicas incluem transações, conexões de BD e gerenciamento de sessão.

Vazamentos de Memória em ThreadLocal

Ocorrem quando entradas chave=null persistem no mapa após remoção do ThreadLocal. Prevenção: use remove() após operações ou declare ThreadLocal como static.

Concorrência, Paralelismo e Serial

Serial: Execução sequencial. Paralelismo: Execução simultânea em múltiplos núcleos. Concorrência: Intercalação de tarefas em único núcleo.

Propriedades da Concorrência

  • Atomicidade: Operações indivisíveis (synchronized)
  • Visibilidade: Alterações visíveis imediatamente (volatile)
  • Ordenação: Prevenção de reordenação de instruções (volatile/synchronized)

Variáveis Volatile

Garante visibilidade imediata de alterações entre threads e previte reordenação de instruções. Não oferece atomicidade para operações compostas.

Fundamentos de ThreadPool

Melhora desempenho reutilizando threads. Parâmetros-chave:

  • corePoolSize: Threads ativas permanentes
  • maxPoolSize: Limite máximo de threads
  • keepAliveTime: Tempo de vida para threads excedentes
  • workQueue: Fila de tarefas pendentes

Fila de Bloqueio em ThreadPools

Armazena tarefas excedentes temporariamente. Prioriza filas sobre criação de novas threads para evitar custos de inicialização e gerenciamento excessivo.

Reutilização de Threads

Threads executam loops internos que consomem tarefas da fila. Evita criação/destruição contínua através de tarefas reutilizáveis.

Tags: java Multithreading Concorrência ThreadPool ThreadLocal

Publicado em 6-29 03:22