Pregunta "Implementa Runnable" vs. "extends Thread"


Desde el momento que he pasado con los hilos en Java, he encontrado estas dos formas de escribir hilos:

Con implements Runnable:

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

O con extends Thread:

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

¿Hay alguna diferencia significativa en estos dos bloques de código?


1794
2018-02-12 14:28


origen


Respuestas:


Sí: implementa Runnable es la forma preferida de hacerlo, IMO. Realmente no estás especializando el comportamiento del hilo. Solo le estás dando algo para correr. Eso significa composición es el filosóficamente "más puro" camino a seguir.

En práctico términos, significa que puede implementar Runnable y se extienden desde otra clase también.


1446
2018-02-12 14:32



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

En general, recomendaría usar algo como Runnable más bien que Thread porque le permite mantener su trabajo solo junto con su elección de concurrencia. Por ejemplo, si usa un Runnable y decida más adelante que esto de hecho no requiere su propio Thread, puedes simplemente llamar a threadA.run ().

Advertencia: Por aquí, desaconsejo firmemente el uso de Threads sin procesar. Yo prefiero el uso de Callables y FutureTasks (Del javadoc: "Un cálculo asincrónico cancelable"). La integración de los tiempos de espera, la cancelación adecuada y la agrupación de subprocesos del soporte de simultaneidad moderno son mucho más útiles para mí que montones de subprocesos sin procesar.

Seguir: hay un FutureTask constructor que le permite usar Runnables (si eso es lo que le hace más cómodo) y aún así obtener el beneficio de las herramientas de simultaneidad modernas. Para citar el javadoc:

Si no necesita un resultado en particular, considere usar construcciones del formulario:

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

Entonces, si reemplazamos su runnable con tu threadA, obtenemos lo siguiente:

new FutureTask<Object>(threadA, null)

Otra opción que te permite estar más cerca de Runnables es una ThreadPoolExecutor. Puedes usar el ejecutar método para pasar en Runnable para ejecutar "la tarea dada alguna vez en el futuro".

Si desea probar el uso de un grupo de subprocesos, el fragmento de código anterior se convertiría en lo siguiente (utilizando el Executors.newCachedThreadPool () método de fábrica):

ExecutorService es = Executors.newCachedThreadPool();
es.execute(new ThreadA());

494
2018-02-12 14:37



Moraleja de la historia:

Heredar solo si desea anular algún comportamiento.

O mejor dicho, debería leerse como:

Heredar menos, interactuar más.


225
2018-03-11 15:50



Bueno, muchas buenas respuestas, quiero agregar más sobre esto. Esto ayudará a entender Extending v/s Implementing Thread.
Extends une dos archivos de clase muy de cerca y puede causar problemas con el código.

Ambos enfoques hacen el mismo trabajo, pero ha habido algunas diferencias.
La diferencia más común es 

  1. Cuando extiendes la clase Thread, después de eso no puedes extender cualquier otra clase que necesites. (Como sabes, Java no permite heredar más de una clase).
  2. Cuando implemente Runnable, puede guardar un espacio para su clase para extender cualquier otra clase en el futuro o ahora.

Sin embargo, uno diferencia significativa entre implementar Runnable y extender Thread es que
  by extending Thread, each of your threads has a unique object associated with it, whereas implementing Runnable, many threads can share the same object instance.

El siguiente ejemplo te ayuda a entender más claramente

//Implement Runnable Interface...
 class ImplementsRunnable implements Runnable {

private int counter = 0;

public void run() {
    counter++;
    System.out.println("ImplementsRunnable : Counter : " + counter);
 }
}

//Extend Thread class...
class ExtendsThread extends Thread {

private int counter = 0;

public void run() {
    counter++;
    System.out.println("ExtendsThread : Counter : " + counter);
 }
}

//Use above classes here in main to understand the differences more clearly...
public class ThreadVsRunnable {

public static void main(String args[]) throws Exception {
    // Multiple threads share the same object.
    ImplementsRunnable rc = new ImplementsRunnable();
    Thread t1 = new Thread(rc);
    t1.start();
    Thread.sleep(1000); // Waiting for 1 second before starting next thread
    Thread t2 = new Thread(rc);
    t2.start();
    Thread.sleep(1000); // Waiting for 1 second before starting next thread
    Thread t3 = new Thread(rc);
    t3.start();

    // Creating new instance for every thread access.
    ExtendsThread tc1 = new ExtendsThread();
    tc1.start();
    Thread.sleep(1000); // Waiting for 1 second before starting next thread
    ExtendsThread tc2 = new ExtendsThread();
    tc2.start();
    Thread.sleep(1000); // Waiting for 1 second before starting next thread
    ExtendsThread tc3 = new ExtendsThread();
    tc3.start();
 }
}

Salida del programa anterior.

ImplementsRunnable : Counter : 1
ImplementsRunnable : Counter : 2
ImplementsRunnable : Counter : 3
ExtendsThread : Counter : 1
ExtendsThread : Counter : 1
ExtendsThread : Counter : 1

En el enfoque de la interfaz Runnable, solo se está creando una instancia de una clase y ha sido compartida por diferentes subprocesos. Por lo tanto, el valor del contador se incrementa para cada acceso de subproceso.

Mientras que, enfoque de la clase de subprocesos, debe crear una instancia separada para cada acceso a subprocesos. Por lo tanto, se asigna memoria diferente para cada instancia de clase y cada una tiene un contador por separado, el valor permanece igual, lo que significa que no se producirá ningún incremento porque ninguna de las referencias del objeto es la misma.

Cuándo usar Runnable?
Use la interfaz Ejecutable cuando desee acceder al mismo recurso del grupo de subprocesos. Evite utilizar la clase Thread aquí, porque la creación de objetos múltiples consume más memoria y se convierte en una gran sobrecarga de rendimiento.

Una clase que implementa Runnable no es un hilo y solo una clase. Para que un Runnable se convierta en un Thread, debe crear una instancia de Thread y pasar a sí mismo como el objetivo.

En la mayoría de los casos, la interfaz Runnable debe usarse si solo planea anular el run() método y no otros métodos de subprocesos. Esto es importante porque las clases no se deben subclasificar a menos que el programador tenga la intención de modificar o mejorar el comportamiento fundamental de la clase.

Cuando hay una necesidad de extender una superclase, implementar la interfaz Runnable es más apropiado que usar la clase Thread. Porque podemos extender otra clase mientras implementamos la interfaz de Runnable para crear un hilo.

¡Espero que esto sea de ayuda!


184
2018-03-05 14:26



Una cosa que me sorprende no se ha mencionado aún es que la implementación Runnable hace que tu clase sea más flexible.

Si extiendes el hilo, entonces la acción que estás haciendo siempre estará en un hilo. Sin embargo, si implementa Runnable no tiene que ser así. Puede ejecutarlo en un subproceso, o pasarlo a algún tipo de servicio de ejecutor, o simplemente pasarlo como una tarea dentro de una aplicación de subproceso único (tal vez para ejecutarse en un momento posterior, pero dentro del mismo subproceso). Las opciones son mucho más abiertas si solo usas Runnable que si te unes a Thread.


73
2018-02-12 14:51



Si quiere implementar o extender cualquier otra clase, entonces Runnable la interfaz es más preferible de lo contrario si no desea que se extienda o implemente otra clase Thread clase es preferible

La diferencia más común es

enter image description here

Cuando tú extends Thread clase, después de eso no puedes extender cualquier otra clase que requieras. (Como sabes, Java no permite heredar más de una clase).

Cuando tú implements Runnable, puede guardar un espacio para su clase para extender cualquier otra clase en el futuro o ahora.

  • Java no es compatible con herencia múltiple, lo que significa que solo puede extender una clase en Java, por lo que una vez que haya extendido la clase Thread, habrá perdido su oportunidad y no podrá extender o heredar otra clase en Java.

  • En la programación orientada a objetos, extender una clase generalmente significa agregar nuevas funcionalidades, modificar o mejorar comportamientos. Si no estamos haciendo ninguna modificación en Thread, entonces use la interfaz Runnable.

  • La interfaz Runnable representa una Tarea que puede ser ejecutada por Thread o Execution o por cualquier otro medio. por lo tanto, la separación lógica de Tarea como Runnable than Thread 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 puede reiniciar un subproceso una vez que se completa. otra vez Runnable vs Thread for task, Runnable es ganador.

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

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

Cortesía de javarevisited.blogspot.com

Estas fueron algunas de las notables diferencias entre Thread y Runnable en Java, si conoce alguna otra diferencia en Thread vs Runnable que la que debe compartir a través de los comentarios. Yo personalmente uso Runnable over Thread para este escenario y le recomiendo usar la interfaz ejecutable o invocable en función de sus necesidades.

Sin embargo, la diferencia significativa es

Cuando tú extends Thread clase, cada uno de sus hilos crea un objeto único y se asocia con él. Cuando tú implements Runnable, comparte el mismo objeto con múltiples hilos.


65
2018-05-11 08:59



En realidad, no es sabio comparar Runnable y Thread juntos.

Estos dos tienen una dependencia y relación en multi-threading al igual que Wheel and Engine relación de vehículo de motor.

Yo diría que solo hay una forma de multi-threading con dos pasos. Déjame hacer mi punto.

Runnable:
Cuando se implementa interface Runnable significa que estás creando algo que es run able en un hilo diferente. Ahora, crear algo que pueda ejecutarse dentro de un hilo (ejecutable dentro de un hilo), no significa crear un hilo.
Entonces la clase MyRunnable no es más que una clase ordinaria con un void run método. Y sus objetos serán algunos objetos ordinarios con solo un método run que se ejecutará normalmente cuando se le llame. (a menos que pasemos el objeto en un hilo).

Hilo:
class Thread, Diría una clase muy especial con la capacidad de iniciar un nuevo subproceso que en realidad permite multi-threading a través de su start() método.

¿Por qué no sabio comparar?
Porque los necesitamos a ambos para multi-threading.

Para Multi-threading necesitamos dos cosas:

  • Algo que se puede ejecutar dentro de un subproceso (ejecutable).
  • Algo que puede iniciar un nuevo subproceso (subproceso).

Entonces, tanto técnica como teóricamente, ambos son necesarios para comenzar un hilo, uno lo hará correr y uno lo hará hazlo correr (Me gusta Wheel and Engine de un vehículo de motor).

Es por eso que no puedes comenzar un hilo con MyRunnable necesitas pasarlo a una instancia de Thread.

Pero es posible crear y ejecutar un hilo solo usando class Thread porque Clase Thread implementos Runnable entonces todos lo sabemos Thread también es un Runnable dentro.

Finalmente Thread y Runnable se complementan entre sí para multihilo no competidor o reemplazo.


61
2018-05-12 13:50



Debe implementar Runnable, pero si está ejecutando en Java 5 o superior, no debe iniciarlo con new Thread pero usa un ExecutorService en lugar. Para detalles, ver: Cómo implementar un subprocesamiento simple en Java.


41
2018-02-12 14:41



No soy un experto, pero puedo pensar en una razón para implementar Runnable en lugar de extender Thread: Java solo admite herencia simple, por lo que solo puedes extender una clase.

Editar: Esto originalmente dijo "Implementar una interfaz requiere menos recursos". también, pero necesita crear una nueva instancia de Thread de cualquier manera, por lo que esto fue incorrecto.


31
2018-02-12 14:32



Yo diría que hay una tercera forma:

public class Something {

    public void justAnotherMethod() { ... }

}

new Thread(new Runnable() {
   public void run() {
    instanceOfSomething.justAnotherMethod();
   }
}).start();

Tal vez esto se ve un poco influenciado por mi reciente uso intensivo de Javascript y Actionscript 3, pero de esta manera su clase no necesita implementar una interfaz bastante vaga como Runnable.


19
2017-10-25 21:41