implements Runnable vs extends Thread: por que 90% dos desenvolvedores Java erram?
\n\nImagine: você está em uma entrevista em uma grande empresa de TI. O recrutador sorri e faz uma pergunta "simples": "Qual a diferença entre implements Runnable e extends Thread em Java?". Parece simples, não? Mas é aqui que, segundo dados do Stack Overflow, até desenvolvedores experientes tropeçam. Milhares de visualizações, centenas de comentários — o tópico "Java Runnable vs Thread" continua sendo um dos mais polêmicos.
\n\nNeste artigo, não vamos apenas listar as diferenças. Vamos analisar os 5 principais erros reais que programadores cometem e mostrar como escrever código multithread limpo e escalável. Se você programa em Java e usa Thread diretamente — leia com atenção. Talvez você nem perceba que está criando problemas para si mesmo.
Breve introdução: o que são Thread e Runnable?
\n\nAntes de mergulhar nos detalhes, vamos refrescar a base. Java Thread é uma classe que representa um fluxo de execução. Ela pode executar código em paralelo. Runnable é uma interface funcional com um único método run(). Ela descreve uma tarefa a ser executada, mas não sabe como executá-la.
Aqui está um exemplo clássico com extends Thread:
public class MyThread extends Thread {\n @Override\n public void run() {\n System.out.println("Thread em execução: " + Thread.currentThread().getName());\n }\n\n public static void main(String[] args) {\n MyThread t = new MyThread();\n t.start(); // Inicia uma nova thread\n }\n}\n\nE aqui está a mesma funcionalidade com implements Runnable:
public class MyTask implements Runnable {\n @Override\n public void run() {\n System.out.println("Tarefa em execução: " + Thread.currentThread().getName());\n }\n\n public static void main(String[] args) {\n Thread t = new Thread(new MyTask());\n t.start();\n }\n}\n\nÀ primeira vista, a diferença é mínima. Mas o diabo, como sempre, está nos detalhes.
\n\nTop 5 erros ao trabalhar com Thread e Runnable
\n\nErro nº1: Herdar Thread quando deveria ser Runnable
\n\nO problema mais comum é o acoplamento rígido com a classe Thread. Quando você escreve extends Thread, sua classe se torna uma thread. Você perde a capacidade de herdar outra classe. Java é uma linguagem com herança única, e isso é uma limitação séria.
Exemplo de código ruim:
\n\npublic class DataProcessor extends Thread {\n // Não pode mais extends JFrame, ArrayList ou outra classe útil\n @Override\n public void run() {\n // processamento de dados\n }\n}\n\nComo deveria ser: Use implements Runnable. É uma interface — você pode implementá-la em qualquer classe que já herde algo.
public class DataProcessor extends BaseService implements Runnable {\n @Override\n public void run() {\n // processamento de dados\n }\n}\n\nErro nº2: Confusão entre run() e start()
\n\nClássico do gênero. Iniciantes (e não só) frequentemente chamam run() em vez de start(). A diferença é crítica: start() cria uma nova thread e, dentro dela, chama run(). Já run() é executado na thread atual, como um método comum.
Exemplo de erro:
\n\nThread t = new Thread(new MyTask());\nt.run(); // Funciona, mas na mesma thread! Não há multithreading.\n\nA saída no console será na thread principal main, não em uma nova. O erro é difícil de detectar porque o código não quebra — ele simplesmente não faz o que você espera.
Como evitar: Sempre use start() para iniciar uma nova thread. Se tiver dúvidas, verifique a documentação.