"implementa Runnable" frente a "extiende Thread" en Java

Resuelto user65374 asked hace 15 años • 42 respuestas

Desde el tiempo que pasé con los hilos en Java, encontré estas dos formas de escribir hilos:

Con implementos Runnable:

public class MyRunnable implements Runnable {
    public void run() {
        //Code
    }
}
//Started with a "new Thread(new MyRunnable()).start()" call

O, con extiende Thread:

public class MyThread extends Thread {
    public MyThread() {
        super("MyThread");
    }
    public void run() {
        //Code
    }
}
//Started with a "new MyThread().start()" call

¿Existe alguna diferencia significativa entre estos dos bloques de código?

user65374 avatar Feb 12 '09 21:02 user65374
Aceptado

Sí: los implementos Runnableson la forma preferida de hacerlo, en mi opinión. Realmente no estás especializando el comportamiento del hilo. Simplemente le estás dando algo para que funcione. Eso significa que la composición es el camino filosóficamente "más puro" a seguir.

En términos prácticos , significa que también puedes implementar Runnabley extender desde otra clase... y también puedes implementar Runnablemediante una expresión lambda a partir de Java 8.

Jon Skeet avatar Feb 12 '2009 14:02 Jon Skeet

tl;dr: implementa Runnable es mejor. Sin embargo, la advertencia es importante .

En general, recomendaría usar algo como Runnableen lugar de Threadporque le permite mantener su trabajo vinculado de manera flexible con su elección de concurrencia. Por ejemplo, si usa a Runnabley decide más adelante que esto en realidad no requiere su propio Thread, puede simplemente llamar a threadA.run().

Advertencia: por aquí, desaconsejo encarecidamente el uso de subprocesos sin formato. Prefiero el uso de Callables y FutureTasks (del javadoc: "Un cálculo asincrónico cancelable"). La integración de tiempos de espera, la cancelación adecuada y la agrupación de subprocesos del soporte de concurrencia moderno son mucho más útiles para mí que montones de subprocesos sin procesar.

Seguimiento: existe un FutureTaskconstructor que le permite usar Runnables (si es con lo que se siente más cómodo) y aún así obtener el beneficio de las herramientas de concurrencia modernas. Para citar el javadoc :

Si no necesita un resultado en particular, considere usar construcciones de la forma:

Future<?> f = new FutureTask<Object>(runnable, null)

Entonces, si reemplazamos su runnablecon su threadA, obtenemos lo siguiente:

new FutureTask<Object>(threadA, null)

Otra opción que te permite estar más cerca de Runnables es ThreadPoolExecutor . Puede utilizar el método de ejecución para pasar un Runnable para ejecutar "la tarea dada en algún momento en el futuro".

Si desea intentar usar un grupo de subprocesos, el fragmento de código anterior sería algo como lo siguiente (usando el método de fábrica Executors.newCachedThreadPool() ):

ExecutorService es = Executors.newCachedThreadPool();
es.execute(new ThreadA());
Bob Cross avatar Feb 12 '2009 14:02 Bob Cross

Moraleja de la historia:

Herede solo si desea anular algún comportamiento.

O mejor dicho debería leerse como:

Hereda menos, interactúa más.

panzerschreck avatar Mar 11 '2010 15:03 panzerschreck

Si desea implementar o ampliar cualquier otra clase, entonces Runnablelo más preferible es la interfaz; de lo contrario, si no desea que ninguna otra clase se extienda o implemente, entonces Threades preferible la clase.

La diferencia más común es

ingrese la descripción de la imagen aquí

Cuando tomas extends Threadclases, después de eso no puedes extender ninguna otra clase que necesites. (Como sabes, Java no permite heredar más de una clase).

Cuando lo hace implements Runnable, puede ahorrar espacio para que su clase pueda ampliar cualquier otra clase en el futuro o ahora.

  • Java no admite herencias múltiples, lo que significa que solo puede extender una clase en Java, por lo que una vez que extendió la clase Thread perdió la oportunidad y no puede extender ni heredar otra clase en Java.

  • En la programación orientada a objetos, ampliar una clase generalmente significa agregar nuevas funcionalidades y modificar o mejorar comportamientos. Si no realizamos ninguna modificación en Thread, utilice la interfaz Runnable.

  • La interfaz ejecutable representa una tarea que puede ejecutarse mediante subprocesos simples o ejecutores o cualquier otro medio. por lo que la separación lógica de Tarea como Ejecutable que de Hilo es una buena decisión de diseño.

  • Separar la tarea como Runnable significa que podemos reutilizar la tarea y también tenemos la libertad de ejecutarla desde diferentes medios. ya que no puedes reiniciar un hilo una vez que se completa. nuevamente Runnable vs Thread para la tarea, Runnable es el ganador.

  • El diseñador de Java reconoce esto y es por eso que los ejecutores aceptan Runnable como tarea y tienen un subproceso de trabajo que ejecuta esas tareas.

  • Heredar todos los métodos de Thread supone una sobrecarga adicional solo para representar una Tarea que se puede realizar fácilmente con Runnable.

Cortesía de javarevisited.blogspot.com

Estas fueron algunas de las diferencias notables entre Thread y Runnable en Java. Si conoce alguna otra diferencia entre Thread y Runnable, compártala a través de los comentarios. Yo personalmente uso Runnable over Thread para este escenario y recomiendo usar la interfaz Runnable o Callable según sus requisitos.

Sin embargo, la diferencia significativa es.

Cuando extends Threadclasificas, cada uno de tus hilos crea un objeto único y se asocia con él. Cuando lo haces implements Runnable, comparte el mismo objeto con varios subprocesos.

Nidhish Krishnan avatar May 11 '2013 08:05 Nidhish Krishnan

Una cosa que me sorprende que aún no se haya mencionado es que la implementación Runnablehace que la clase sea más flexible.

Si extiendes el hilo, la acción que estás realizando siempre estará en un hilo. Sin embargo, si lo implementa, Runnableno tiene por qué ser así. Puede ejecutarlo en un subproceso, o pasarlo a algún tipo de servicio ejecutor, o simplemente pasarlo como una tarea dentro de una aplicación de un solo subproceso (tal vez para ejecutarlo más adelante, pero dentro del mismo subproceso). Las opciones son mucho más abiertas si solo las usas Runnableque si te vinculas a Thread.

Herms avatar Feb 12 '2009 14:02 Herms

En realidad, no es prudente compararse Runnableentre Threadsí.

Estos dos tienen una dependencia y relación en subprocesos múltiples al igual que Wheel and Enginela relación de un vehículo de motor.

Yo diría que solo hay una forma de realizar subprocesos múltiples con dos pasos. Déjame aclarar mi punto.

Ejecutable:
al implementarlo interface Runnablesignifica que estás creando algo que está run ableen un hilo diferente. Ahora bien, crear algo que pueda ejecutarse dentro de un subproceso (ejecutable dentro de un subproceso) no significa crear un subproceso.
Entonces la clase MyRunnableno es más que una clase ordinaria con un void runmétodo. Y sus objetos serán algunos objetos ordinarios con solo un método runque se ejecutará normalmente cuando se llame. (a menos que pasemos el objeto en un hilo).

Subproceso:
class Thread Yo diría que es una clase muy especial con la capacidad de iniciar un nuevo subproceso que en realidad permite subprocesos múltiples a través de su start()método.

¿Por qué no es prudente comparar?
Porque los necesitamos a ambos para subprocesos múltiples.

Para subprocesos múltiples necesitamos dos cosas:

  • Algo que puede ejecutarse dentro de un Thread (Runnable).
  • Algo Que pueda iniciar un nuevo Hilo (Thread).

Entonces, técnica y teóricamente ambos son necesarios para iniciar un hilo, uno lo ejecutará y el otro lo hará funcionar (como Wheel and Engineen un vehículo de motor).

Es por eso que no puedes iniciar un hilo; MyRunnabledebes pasarlo a una instancia de Thread.

Pero es posible crear y ejecutar un hilo solo class Threadporque Class Threadse implementa, Runnablepor lo que todos sabemos que Threadtambién es Runnableinterno.

Finalmente Thread, son Runnablecomplementos entre sí para subprocesos múltiples, no competidores ni reemplazos.

Saif avatar May 12 '2015 13:05 Saif