Encerramento de Threads em Java: Métodos Seguros e Práticas Recomendadas

Encerramento de Threads em Java

Em Java, encerrar threads de forma segura é essencial para evitar problemas de concorrência e inconsistência de dados. O método stop() da classe Thread foi descontinuado por causar liberação de locks e interromper código crítico de maneira perigosa. Abaixo, exploramos alternativas viáveis.

  1. Uso de Flag de Saída

Uma abordagem comum é utilizar uma variável de controle (flag) para sinalizar a thread quando ela deve finalizar. A thread verifica essa flag em cada iteração de seu laço principal.

public class WorkerThread extends Thread {
    private volatile boolean running = true;

    public void stopThread() {
        running = false;
    }

    public void run() {
        while (running) {
            // Executa tarefas aqui
        }
        System.out.println("Thread finalizada.");
    }
}

// Uso no código principal
WorkerThread worker = new WorkerThread();
worker.start();
Thread.sleep(5000); // Espera 5 segundos
worker.stopThread();
worker.join();

A palavra-chave volatile garante que alterações na flag sejam visíveis imediatamente em todas as threads.

  1. Método interrupt()

O método interrupt() é a forma recomendada para interromper threads, especialmente quando estão em estados de bloqueio como sleep() ou wait().

2.1 Threads em Estado de Bloqueio

Se a thread está dormindo ou esperando, chamar interrupt() lança uma InterruptedException. Capturar essa exceção permite encerrar a thread de forma controlada.

public class InterruptibleTask extends Thread {
    public void run() {
        try {
            Thread.sleep(60000); // Dorme por 60 segundos
        } catch (InterruptedException e) {
            System.out.println("Thread interrompida durante o sleep.");
        }
        System.out.println("Execução concluída.");
    }
}

// No código principal
InterruptibleTask task = new InterruptibleTask();
task.start();
task.interrupt(); // Interrompe a thread
task.join();

2.2 Threads em Execução Ativa

Para threads em laços contínuos, combine interrupt() com a verificação de isInterrupted().

public class ActiveWorker extends Thread {
    public void run() {
        while (!Thread.currentThread().isInterrupted()) {
            // Processamento contínuo
        }
        System.out.println("Thread encerrada por interrupção.");
    }
}

  1. Considerações para I/O Bloqueante

Operações de I/O bloqueante (ex.: leitura de sockets) podem não responder a interrupt() em todas as plataformas. Uma solução é usar canais interrompíveis (InterruptibleChannel).

import java.io.*;
import java.nio.channels.*;

public class InterruptibleIO {
    public static void main(String[] args) throws Exception {
        FileInputStream fis = new FileInputStream(FileDescriptor.in);
        InterruptibleChannel channel = fis.getChannel();
        BufferedReader reader = new BufferedReader(
            new InputStreamReader(Channels.newInputStream(channel))
        );

        Thread readerThread = new Thread(() -> {
            try {
                String line = reader.readLine();
                System.out.println("Linha: " + line);
            } catch (ClosedByInterruptException e) {
                System.out.println("I/O interrompido pelo canal.");
            } catch (IOException e) {
                e.printStackTrace();
            }
        });

        readerThread.start();
        Thread.sleep(2000);
        readerThread.interrupt();
        readerThread.join();
    }
}

  1. Padrão de Encerramento com Dupla Verificação

Para garantir que a thread realmente pare, combine uma flag volátil com interrupt().

public class ReliableThread extends Thread {
    private volatile boolean terminated = false;

    public void terminate() {
        terminated = true;
        interrupt(); // Acorda threads bloqueadas
    }

    public void run() {
        while (!terminated && !isInterrupted()) {
            try {
                Thread.sleep(100);
                // Trabalho aqui
            } catch (InterruptedException e) {
                System.out.println("Interrompido.");
                break; // Sai do laço
            }
        }
        System.out.println("Thread finalizada de forma segura.");
    }
}

Conclusão Técnica

Evite métodos como stop() ou suspend(). Utilize flags voláteis e interrupt() adaptados ao contexto da thread. Teste cuidadosamente para evitar estados inconsistentes.

Tags: java threads Concurrency Interrupt volatile

Publicado em 6-18 01:15