implements Runnable vs extends Thread: ¿por qué el 90% de los desarrolladores Java se equivoca?
\n\nImagina: estás en una entrevista en una gran empresa de TI. El reclutador sonríe y hace una pregunta "sencilla": "¿Cuál es la diferencia entre implements Runnable y extends Thread en Java?". Parece simple, ¿verdad? Pero aquí, según datos de Stack Overflow, incluso desarrolladores experimentados tropiezan. Miles de visitas, cientos de comentarios: el tema "Java Runnable vs Thread" sigue siendo uno de los más candentes.
\n\nEn este artículo no solo enumeraremos las diferencias. Analizaremos los 5 errores reales más comunes que cometen los programadores y mostraremos cómo escribir código concurrente limpio y escalable. Si programas en Java y usas Thread directamente, lee con atención. Quizás sin darte cuenta te estás creando problemas.
Breve introducción: ¿qué son Thread y Runnable?
\n\nAntes de profundizar, refresquemos lo básico. Java Thread es una clase que representa un hilo de ejecución. Puede ejecutar código en modo paralelo. Runnable es una interfaz funcional con un único método run(). Describe una tarea que debe ejecutarse, pero no sabe cómo iniciarla.
Aquí tienes un ejemplo clásico con extends Thread:
public class MyThread extends Thread {\n @Override\n public void run() {\n System.out.println("El hilo está funcionando: " + Thread.currentThread().getName());\n }\n\n public static void main(String[] args) {\n MyThread t = new MyThread();\n t.start(); // Inicia un nuevo hilo\n }\n}\n\nY la misma funcionalidad con implements Runnable:
public class MyTask implements Runnable {\n @Override\n public void run() {\n System.out.println("La tarea se ejecuta: " + 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\nA primera vista, la diferencia es mínima. Pero el diablo, como siempre, está en los detalles.
\n\nTop 5 errores al trabajar con Thread y Runnable
\n\nError n.º 1: Heredar de Thread cuando se necesita Runnable
\n\nEl problema más común es el acoplamiento rígido con la clase Thread. Cuando usas extends Thread, tu clase se convierte en un hilo. Pierdes la posibilidad de heredar de otra clase. Java es un lenguaje con herencia única, y esto es una limitación grave.
Ejemplo de código incorrecto:
\n\npublic class DataProcessor extends Thread {\n // Ya no se puede extender JFrame, ArrayList u otra clase útil\n @Override\n public void run() {\n // procesamiento de datos\n }\n}\n\nCómo debería ser: Usa implements Runnable. Es una interfaz: puedes implementarla en cualquier clase que ya herede de otra cosa.
public class DataProcessor extends BaseService implements Runnable {\n @Override\n public void run() {\n // procesamiento de datos\n }\n}\n\nError n.º 2: Confundir run() con start()
\n\nUn clásico. Los novatos (y no solo ellos) suelen llamar a run() en lugar de start(). La diferencia es crítica: start() crea un nuevo hilo y dentro de él llama a run(). run() se ejecuta en el hilo actual, como un método normal.
Ejemplo de error:
\n\nThread t = new Thread(new MyTask());\nt.run(); // Funciona, pero en el mismo hilo. ¡No hay concurrencia!\n\nLa salida en consola será en el hilo principal main, no en uno nuevo. El error es difícil de detectar porque el código no falla, simplemente no hace lo que esperas.
Cómo evitarlo: Usa siempre start() para iniciar un nuevo hilo. Si tienes dudas