new - thread java




"Implementa Runnable" vs "extiende Thread" en Java (20)

Del tiempo que he pasado con 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?


  1. Java no admite la herencia múltiple, lo que significa que solo puede extender una clase en Java, así que una vez que extendió la clase Thread perdió su oportunidad y no puede extender o heredar otra clase en Java.
  2. En la programación orientada a objetos, extender una clase generalmente significa agregar nueva funcionalidad, modificar o mejorar los comportamientos. Si no estamos haciendo ninguna modificación en Thread use la interfaz Runnable .
  3. Runnable interfaz Runnable representa una Task que puede ser ejecutada por un solo Thread o por Executors o por cualquier otro medio. La separación lógica de Task como Runnable que Thread es una buena decisión de diseño.
  4. Separar tarea como Runnable significa que podemos reutilizar la tarea y también tenemos libertad para ejecutarla desde diferentes medios. Ya que no puede reiniciar un Thread una vez que se complete, nuevamente Runnable vs Thread para la tarea, Runnable es el ganador.
  5. El diseñador Java reconoce esto y es por eso que los Executors aceptan Runnable como Task y tienen un hilo de trabajo que ejecuta esas tareas.
  6. La herencia de todos los métodos Thread Runnable una sobrecarga adicional solo para representar una Task que se puede hacer fácilmente con Runnable .

Bueno, tantas buenas respuestas, quiero agregar más sobre esto. Esto ayudará a comprender Extending v/s Implementing Thread .
Extiende los enlaces de dos archivos de clase muy estrechamente y puede causar algunos bastante difíciles de tratar con el código.

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

  1. Cuando extiende la clase Thread, después de eso no puede extender ninguna otra clase que requiera. (Como saben, Java no permite heredar más de una clase).
  2. Cuando implementa Runnable, puede guardar un espacio para su clase para extender cualquier otra clase en el futuro o ahora.

Sin embargo, una diferencia significativa entre la implementación de Runnable y la extensión de 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 crea una instancia de una clase y ha sido compartida por diferentes hilos. Por lo tanto, el valor del contador se incrementa para cada acceso a todos los subprocesos.

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

¿Cuándo usar Runnable?
Utilice la interfaz Runnable cuando desee acceder al mismo recurso desde el grupo de subprocesos. Evite usar la clase Thread aquí, porque la creación de múltiples objetos 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 destino.

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

Cuando existe la 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 Runnable para hacer un hilo.

¡Espero que esto sea de ayuda!



Ejecutable porque:

  • Deja más flexibilidad para que la implementación Runnable extienda otra clase.
  • Separa el código de la ejecución.
  • Le permite ejecutar su runnable desde un Thread Pool, el thread de eventos, o de cualquier otra forma en el futuro.

Incluso si no necesita nada de esto ahora, puede hacerlo en el futuro. Dado que no hay ningún beneficio en anular Thread, Runnable es una mejor solución.


La creación de una interfaz proporciona una separación más clara entre su código y la implementación de subprocesos, por lo que prefiero implementar Runnable en este caso.


Moraleja de la historia:

Hereda solo si desea anular algún comportamiento.

O más bien debería leerse como:

Heredar menos, interactuar más.


Sí: implementa Runnable es la forma preferida de hacerlo, IMO. No estás realmente especializando el comportamiento del hilo. Solo le das algo para correr. Eso significa que la composition es el camino filosóficamente "más puro".

En términos prácticos , significa que puede implementar Runnable y extenderse desde otra clase también.


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

La diferencia más común es

Cuando extends Thread clase extends Thread , después de eso no puede extender ninguna otra clase que requiera. (Como saben, Java no permite heredar más de una clase).

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

  • Java no admite la herencia múltiple, lo que significa que solo puede extender una clase en Java, así que una vez que extendió la clase Thread perdió su oportunidad y no puede extender o heredar otra clase en Java.

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

  • La interfaz ejecutable representa una tarea que puede ser ejecutada por un solo hilo o por ejecutores o por cualquier otro medio. la separación lógica de Tarea como Ejecutable que Hilo es una buena decisión de diseño.

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

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

  • La herencia de todos los métodos Thread conlleva 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 diferencias notables entre Thread y Runnable en Java, si conoce alguna otra diferencia en Thread vs Runnable que comparta a través de los comentarios. Personalmente uso Runnable over Thread para este escenario y recomiendo usar la interfaz Runnable o Callable en función de sus requisitos.

Sin embargo, la diferencia significativa es.

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


Una cosa que me sorprende aún no se ha mencionado es que la implementación de Runnable hace que su 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 implementas Runnable no tiene que ser. Puede ejecutarlo en un hilo, o pasarlo a algún tipo de servicio de ejecutor, o simplemente pasarlo como una tarea dentro de una aplicación de un solo hilo (tal vez se ejecute más adelante, pero dentro del mismo hilo). Las opciones son mucho más abiertas si solo usas Runnable que si te Runnable a Thread .


Ya que este es un tema muy popular y las buenas respuestas se extienden y se tratan en gran profundidad, sentí que es justificable compilar las buenas respuestas de los demás en una forma más concisa, para que los recién llegados tengan una visión general sencilla por adelantado:

  1. Por lo general, se extiende una clase para agregar o modificar la funcionalidad. Por lo tanto, si no desea sobrescribir ningún comportamiento de Thread , use Runnable.

  2. De la misma manera, si no necesita heredar métodos de subprocesos, puede hacerlo sin esa sobrecarga utilizando Runnable.

  3. Herencia única : si extiendes Thread no puedes extender desde ninguna otra clase, así que si eso es lo que necesitas hacer, debes usar Runnable.

  4. Es un buen diseño separar la lógica del dominio de los medios técnicos, en ese sentido, es mejor tener una tarea Ejecutable que aísle la tarea de su corredor .

  5. Puede ejecutar el mismo objeto Runnable varias veces , un objeto Thread, sin embargo, solo se puede iniciar una vez. (Quizás la razón, la razón por la cual los Ejecutores aceptan Runnables, pero no Hilos).

  6. Si desarrolla su tarea como Runnable, tiene toda la flexibilidad para usarla ahora y en el futuro . Puede ejecutarse simultáneamente mediante Ejecutores, pero también mediante Subproceso. Y también podría usar / llamarlo de forma no simultánea dentro del mismo hilo al igual que cualquier otro tipo / objeto común.

  7. Esto también facilita la separación de los aspectos de lógica de tareas y concurrencia en sus pruebas unitarias .

  8. Si está interesado en esta pregunta, también podría estar interesado en la diferencia entre Callable y Runnable .


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

En general, recomendaría usar algo como Runnable lugar de Thread porque le permite mantener su trabajo acoplado libremente con su elección de concurrencia. Por ejemplo, si usa un Runnable y luego decide que esto no requiere su propio Thread , puede llamar a threadA.run ().

Advertencia: por aquí, desaliento fuertemente el uso de hilos crudos. Prefiero el uso de Callables y FutureTasks (desde el javadoc: "Un cálculo asíncrono cancelable"). La integración de los 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 las pilas de subprocesos sin procesar.

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

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

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

Por lo tanto, si reemplazamos su runnable con su threadA , obtenemos lo siguiente:

new FutureTask<Object>(threadA, null)

Otra opción que te permite estar más cerca de Runnables es un ThreadPoolExecutor . Puede usar el método de execute 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 se convertiría en algo similar a lo siguiente (utilizando el método de fábrica Executors.newCachedThreadPool() ):

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

Encuentro que es más útil usar Runnable por todas las razones mencionadas, pero a veces me gusta extender Thread para poder crear mi propio método de detención de threads y llamarlo directamente al thread que he creado.


La diferencia entre la extensión del hilo y la ejecución ejecutable son:


Si no me equivoco, es más o menos similar a

¿Cuál es la diferencia entre una interfaz y una clase abstracta?

amplia establece la relación " Is A " y la interfaz proporciona " Tiene una " capacidad.

Prefiere implementos Runnable :

  1. Si no tiene que extender la clase Thread y modificar la implementación predeterminada de Thread API
  2. Si está ejecutando un comando de fuego y olvido
  3. Si ya estás extendiendo otra clase.

Prefiere " extiende Hilo ":

  1. Si tiene que anular cualquiera de estos métodos Thread como se indica en la página de documentación de Oracle

En general, no es necesario anular el comportamiento de Hilo. Por lo tanto, los implementos Runnable se prefieren la mayoría de las veces.

En una nota diferente, el uso avanzado ExecutorServiceo ThreadPoolExecutorServiceAPI proporciona más flexibilidad y control.

Echa un vistazo a esta pregunta SE:

ExecutorService vs Casual Thread Spawner


Una diferencia entre la implementación de Runnable y la extensión de Thread es que al extender Thread, cada uno de sus threads tiene un objeto único asociado, mientras que la implementación de Runnable, muchos threads pueden compartir la misma instancia de objeto.

Una clase que implementa Runnable no es un hilo y solo una clase. Para que un Runnable sea ejecutado por un Thread, debe crear una instancia de Thread y pasar la instancia de Runnable como destino.

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

Cuando existe la 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 Runnable para hacer un hilo. Pero si solo extendemos la clase Thread no podemos heredar de ninguna otra clase.


¿Podemos volver a visitar la razón básica por la que queríamos que nuestra clase se comportara como un Thread? No hay ninguna razón en absoluto, solo queríamos ejecutar una tarea, lo más probable es que en un modo asíncrono, lo que precisamente significa que la ejecución de la tarea debe derivarse de nuestro hilo principal y el hilo principal si finaliza pronto, puede o no puede esperar para el camino ramificado (tarea).

Si este es todo el propósito, entonces ¿dónde veo la necesidad de un hilo especializado? Esto puede lograrse recogiendo un subproceso RAW del grupo de subprocesos del sistema y asignándole nuestra tarea (puede ser una instancia de nuestra clase) y eso es todo.

Así que obedezcamos el concepto OOP y escribamos una clase del tipo que necesitamos. Hay muchas maneras de hacer las cosas, hacerlo de la manera correcta importa.

Necesitamos una tarea, así que escriba una definición de tarea que se pueda ejecutar en un Thread. Entonces usa Runnable.

Recordar siempre implementsse utiliza especialmente para impartir un comportamiento y extendsse utiliza para impartir una característica / propiedad.

No queremos la propiedad del hilo, en lugar de eso queremos que nuestra clase se comporte como una tarea que se puede ejecutar.


Diferencia entre Thread y Runnable. Si estamos creando Thread usando la clase Thread, entonces el número de thread es igual al número de objeto que creamos. Si estamos creando subprocesos implementando la interfaz ejecutable, podemos usar un solo objeto para crear varios subprocesos. Por lo tanto, un solo subproceso lo comparte. Por lo tanto, se necesitará menos memoria.

Dependiendo del requerimiento si nuestros datos no son sensibles. Por lo tanto, se puede compartir entre varios subprocesos que podemos utilizar interfaz Runnable.


Esa es la S de SOLID : responsabilidad única.

Un hilo encarna el contexto en ejecución (como en el contexto de ejecución: marco de pila, id de hilo, etc.) de la ejecución asíncrona de un fragmento de código. Esa pieza de código idealmente debería ser la misma implementación, ya sea síncrona o asíncrona .

Si los agrupa en una implementación, le da al objeto resultante dos causas de cambio no relacionadas :

  1. manejo de subprocesos en su aplicación (es decir, consultar y modificar el contexto de ejecución)
  2. Algoritmo implementado por la pieza de código (la parte ejecutable)

Si el lenguaje que usa admite clases parciales o herencia múltiple, entonces puede segregar cada causa en su propia súper clase, pero se reduce a lo mismo que componer los dos objetos, ya que sus conjuntos de características no se superponen. Eso es para la teoría.

En la práctica, en términos generales, un programa no necesita tener más complejidad de la necesaria. Si tiene un subproceso trabajando en una tarea específica, sin cambiar esa tarea, es probable que no tenga sentido que las tareas se separen de las clases y su código sea más sencillo.

En el contexto de Java , dado que la instalación ya está allí , probablemente sea más fácil comenzar directamente con Runnableclases independientes y pasar sus instancias a Thread(o Executor) instancias. Una vez que se utiliza para ese patrón, no es más difícil de usar (o incluso leer) que el caso de hilo ejecutable simple.


La separación de la clase Thread de la implementación de Runnable también evita posibles problemas de sincronización entre el thread y el método run (). Un Runnable separado generalmente proporciona una mayor flexibilidad en la forma en que se hace referencia y se ejecuta el código ejecutable.


Sí, si llama a la llamada ThreadA, entonces no necesita llamar al método de inicio y el método de ejecución es llamada después de la clase ThreadA. Pero si usa la llamada ThreadB, entonces necesita el hilo de inicio para el método de ejecución de llamada. Si tienes más ayuda, contéstame.







java-threads