¿Cuál es la diferencia entre Thread start () y Runnable run ()

224

Digamos que tenemos estos dos Runnables:

class R1 implements Runnable {
    public void run() {  }
    
}

class R2 implements Runnable {
    public void run() {  }
    
}

Entonces, ¿cuál es la diferencia entre esto:

public static void main() {
    R1 r1 = new R1();
    R2 r2 = new R2();

    r1.run();
    r2.run();
}

Y esto:

public static void main() {
    R1 r1 = new R1();
    R2 r2 = new R2();
    Thread t1 = new Thread(r1);
    Thread t2 = new Thread(r2);

    t1.start();
    t2.start();
}
Ori Popowski
fuente

Respuestas:

309

Primer ejemplo: sin hilos múltiples. Ambos se ejecutan en un solo hilo (existente). Sin creación de hilo.

R1 r1 = new R1();
R2 r2 = new R2();

r1y r2son solo dos objetos diferentes de clases que implementan la Runnableinterfaz y, por lo tanto, implementan el run()método. Cuando llamas, r1.run()lo estás ejecutando en el hilo actual.

Segundo ejemplo: dos hilos separados.

Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);

t1y t2son objetos de la clase Thread. Cuando llama t1.start(), inicia un nuevo hilo y llama al run()método de r1ejecución interna para ejecutarlo dentro de ese nuevo hilo.

Bhesh Gurung
fuente
55
¿Podría considerar que antes de llamar a Thread # start (), no sucede nada realmente relacionado con el hilo del sistema operativo? Es solo un objeto java.
Jaskey
44
Eso es correcto según la documentación. Verifique el código de inicialización del objeto de hilo, que se ajusta a la documentación. También en el código fuente, es el start(), que llama a un método natvie, que debe hacer que sucedan las cosas relacionadas con el hilo del sistema operativo.
Bhesh Gurung
3
El constructor de hilos está aquí . La fuente de inicialización del objeto de subproceso está aquí . start()La fuente del método está aquí .
Bhesh Gurung
92

Si solo invoca run()directamente, se ejecuta en el hilo de llamada, al igual que cualquier otra llamada a método. Thread.start()es necesario para crear un nuevo subproceso para que el runmétodo ejecutable se ejecute en paralelo.

Mike Daniels
fuente
2
En Hotspot JVM, hay una asignación directa entre el hilo de Java y el hilo nativo. Thread.start()la invocación hace que el estado del hilo se mueva del nuevo estado al estado Ejecutable . Runnable no significa que el hilo se esté ejecutando. Una vez que el hilo nativo se ha inicializado, el hilo nativo invoca el run()método en el hilo Java, lo que hace que el estado del hilo cambie de Runnable a Running . Cuando el subproceso finaliza, se liberan todos los recursos para el subproceso nativo y Java.
intercambio excesivo el
@overexchange ¿Dónde puedo encontrar el material sobre el cambio de estado?
twlkyao 01 de
73

La diferencia es que Thread.start()inicia un hilo que llama al run()método, mientras que Runnable.run()solo llama al run()método en el hilo actual.

Marqués de Lorne
fuente
35

La diferencia es que cuando el programa llama al start()método, se crea un nuevo subproceso y el código interno run()se ejecuta en un nuevo subproceso, mientras que si llama al run()método directamente, no se creará un nuevo subproceso y el código interno run()se ejecutará directamente en el subproceso actual.

Otra diferencia entre start()y run()en el hilo de Java es que no puede llamar start()dos veces. Una vez iniciada, la segunda start()llamada incluirá IllegalStateExceptionJava, mientras que puede llamar al run()método varias veces, ya que es solo un método ordinario .

Jaimin Patel
fuente
21

Realmente Thread.start()crea un nuevo hilo y tiene su propio escenario de ejecución.

Thread.start()llama al run()método de forma asincrónica, lo que cambia el estado del nuevo Thread a Runnable.

Pero Thread.run()no crea ningún nuevo hilo. En su lugar, ejecuta el método de ejecución en el subproceso actual en ejecución sincrónicamente.

Si está utilizando, Thread.run()entonces no está utilizando las funciones de subprocesamiento múltiple en absoluto.

aditya
fuente
8

invoke run()se ejecuta en el hilo de llamada, como cualquier otra llamada a método. mientras que Thread.start()crea un nuevo hilo. Invocar run()es un error programático.

Narendra Jaggi
fuente
7

Si lo hace run()en el método principal, el hilo del método principal invocará el runmétodo en lugar del hilo que necesita ejecutar.

El start()método crea un nuevo hilo y para el cual elrun() método debe hacerse

Rohith
fuente
El 'método principal' no tiene nada que ver con eso.
Marqués de Lorne
3
@EJP, por mainel escritor se refería al método de llamada. Su respuesta es bastante buena. +1 ;-)
dom_beau
1
@dom_beau Si eso es lo que quiso decir, debería haberlo dicho. Lo que dijo fue incorrecto. No hay nada "bastante bueno" en esta respuesta. Es solo un desastre confuso.
Marqués de Lorne
5

t.start() es el método que la biblioteca proporciona para que su código llame cuando desee un nuevo hilo.

r.run()es el método que se proporciona para la biblioteca para llamar en el nuevo hilo.


La mayoría de estas respuestas pasan por alto el panorama general, que es que, en lo que respecta al lenguaje Java, no hay más diferencia entre t.start()y r.run()entre cualquier otro método.

Ambos son solo métodos. Ambos corren en el hilo que los llamó . Ambos hacen lo que sea que hayan sido codificados, y luego ambos regresan, aún en el mismo hilo, a sus interlocutores.

La mayor diferencia es que la mayoría del código t.start()es código nativo , mientras que, en la mayoría de los casos, el código r.run()será Java puro. Pero eso no es una gran diferencia. El código es el código. El código nativo es más difícil de encontrar y más difícil de entender cuando lo encuentra, pero sigue siendo solo un código que le dice a la computadora qué hacer.

Entonces, ¿qué hace t.start()?

Crea un nuevo subproceso nativo, organiza la llamada de ese subproceso t.run()y luego le dice al sistema operativo que deje que se ejecute el nuevo subproceso. Entonces vuelve.

¿Y que hace r.run()?

Lo curioso es que la persona que hace esta pregunta es la persona que la escribió . r.run()hace lo que usted (es decir, el desarrollador que lo escribió) diseñó para hacer.

Salomón lento
fuente
4

Thread.start()El código registra el hilo con el planificador y el planificador llama al run()método. Además, Threades clase mientras que Runnablees una interfaz.

CHANDRAHAS
fuente
3

Los puntos que los miembros hicieron están bien, así que solo quiero agregar algo. El caso es que JAVA no admite herencia múltiple. Pero, ¿qué sucede si desea derivar una clase B de otra clase A, pero solo puede derivar de una clase? El problema ahora es cómo "derivar" de ambas clases: A y Thread. Por lo tanto, puede usar la interfaz Runnable.

public class ThreadTest{
   public void method(){
      Thread myThread = new Thread(new B());
      myThread.start;
   }
}

public class B extends A implements Runnable{...
pommoisel
fuente
explicación agradable del método run () con la ayuda de un ejemplo sobre Runnable - una interfaz y Thread - una clase
Pinky Walve
1

Si llama directamente al run()método, no está utilizando la función de subprocesos múltiples desderun() método se ejecuta como parte del hilo de la persona que llama.

Si llama al start()método en Thread, la máquina virtual Java llamará al método run () y dos subprocesos se ejecutarán simultáneamente: el subproceso actual ( main()en su ejemplo) y otro subproceso (ejecutabler1 en su ejemplo).

Eche un vistazo al código fuente del start()método en la clase Thread

 /**
     * Causes this thread to begin execution; the Java Virtual Machine
     * calls the <code>run</code> method of this thread.
     * <p>
     * The result is that two threads are running concurrently: the
     * current thread (which returns from the call to the
     * <code>start</code> method) and the other thread (which executes its
     * <code>run</code> method).
     * <p>
     * It is never legal to start a thread more than once.
     * In particular, a thread may not be restarted once it has completed
     * execution.
     *
     * @exception  IllegalThreadStateException  if the thread was already
     *               started.
     * @see        #run()
     * @see        #stop()
     */
    public synchronized void start() {
        /**
         * This method is not invoked for the main method thread or "system"
         * group threads created/set up by the VM. Any new functionality added
         * to this method in the future may have to also be added to the VM.
         *
         * A zero status value corresponds to state "NEW".
         */
        if (threadStatus != 0)
            throw new IllegalThreadStateException();
        group.add(this);
        start0();
        if (stopBeforeStart) {
            stop0(throwableFromStop);
        }
    }

    private native void start0();

En el código anterior, no puede ver la invocación al run()método.

private native void start0()Es responsable del run()método de llamada . JVM ejecuta este método nativo.

Ravindra babu
fuente
0

En el primer caso, solo está invocando el run()método de r1yr2 objetos.

¡En el segundo caso, en realidad estás creando 2 nuevos hilos!

start()llamará run()en algún momento!

Marsellus Wallace
fuente
77
En realidad, start () no llamará a run (): si lo hiciera, entonces el método run () sería ejecutado por el mismo hilo que llamó a start (). Lo que start () hará es crear un hilo que llamará al método run ().
Bruno Reis
0

método de ejecución: es un método abstracto creado originalmente en la interfaz Runnable y anulado en la clase Thread, así como en las subclases Thread (como Thread implementa Runnable en su código fuente) y cualquier otra clase de implementación de la interfaz Runnable. - Se utiliza para cargar el subproceso (objeto ejecutable) con la tarea que está destinado a hacer, por lo que lo anula para escribir esa tarea.

Método de inicio: se define en la clase Thread. Cuando se llama al método start en un objeto Thread 1- , llama al método interno nativo (no java) llamado start0 (); método.

inicio0 (); Método: es responsable del bajo procesamiento (creación de pila para un subproceso y asignación de subproceso en la cola del procesador) en este punto tenemos un subproceso en estado Listo / Ejecutable.

2- En un momento en que el planificador de subprocesos decide que un subproceso ingresa al núcleo del procesador según el método de ejecución (prioridad del subproceso, así como el algoritmo de programación del sistema operativo) se invoca en el objeto Runnable (ya sea el objeto del subproceso Runnable actual o el objeto Runnable pasado al constructor de subprocesos) aquí un subproceso entra en un estado de ejecución y comienza a ejecutar su tarea (método de ejecución)

Esraa Salama
fuente
-2

Los métodos separados start () y run () en la clase Thread proporcionan dos formas de crear programas enhebrados. El método start () comienza la ejecución del nuevo hilo y llama al método run (). El método start () regresa inmediatamente y el nuevo hilo normalmente continúa hasta que el método run () regresa.

El método run () de la clase Thread no hace nada, por lo que las subclases deben anular el método con el código para ejecutar en el segundo hilo. Si se crea una instancia de un subproceso con un argumento Runnable, el método run () del subproceso ejecuta el método run () del objeto Runnable en el nuevo subproceso.

Dependiendo de la naturaleza de su programa de subprocesos, llamar directamente al método Thread run () puede dar el mismo resultado que llamar a través del método start (), pero en este último caso el código se ejecuta realmente en un nuevo subproceso.

gtzinos
fuente
2
Llamar a 'run ()' no es una forma de crear programas enhebrados. Solo hay una manera.
Marqués de Lorne
-2

Llamada al método Start () método de anulación de ejecución de la clase extendida Thread y la interfaz de implementos Runnable.

Pero al llamar a run () busca el método de ejecución, pero si la clase implementa la interfaz Runnable, llama al método de anulación run () de Runnable.

ex.:

``

public class Main1
{
A a=new A();
B b=new B();
a.run();//This call run() of Thread because run() of Thread only call when class 
        //implements with Runnable not when class extends Thread.
b.run();//This not run anything because no run method found in class B but it 
        //didn't show any error.

a.start();//this call run() of Thread
b.start();//this call run() of Thread
}

class A implements Runnable{
@Override
    public void run() {
            System.out.println("A ");
    }
}

class B extends Thread {

    @Override
    public void run() {
            System.out.println("B ");
    }
}

``

ankit
fuente