¿Es legal llamar al método de inicio dos veces en el mismo hilo?


90

El siguiente código conduce a java.lang.IllegalThreadStateException: Thread already startedcuando llamé al start()método por segunda vez en el programa.

updateUI.join();    

if (!updateUI.isAlive()) 
    updateUI.start();

Esto sucede la segunda vez que updateUI.start()se llama. Lo he pasado varias veces y el hilo se llama y se ejecuta completamente antes de golpear updateUI.start().

Llamar updateUI.run()evita el error pero hace que el hilo se ejecute en el hilo de la interfaz de usuario (el hilo de llamada, como se menciona en otras publicaciones en SO), que no es lo que quiero.

¿Se puede iniciar un hilo solo una vez? Si es así, ¿qué hago si quiero volver a ejecutar el hilo? Este hilo en particular está haciendo algunos cálculos en segundo plano, si no lo hago en el hilo, entonces se hace en el hilo de la interfaz de usuario y el usuario tiene una espera irrazonablemente larga.


9
¿Por qué no acaba de leer el javadoc? Describe claramente el contrato.
mP.

Respuestas:


112

De la especificación de la API de Java para el Thread.startmétodo:

Nunca es legal iniciar un hilo más de una vez. En particular, es posible que un hilo no se reinicie una vez que haya completado la ejecución.

Además:

Lanza:
IllegalThreadStateException- si el hilo ya se inició.

Entonces sí, Threadsolo se puede iniciar una vez.

Si es así, ¿qué hago si quiero volver a ejecutar el hilo?

Si es Threadnecesario ejecutar a más de una vez, entonces uno debe crear una nueva instancia de Threade invocarlo start.


Gracias. Verifiqué la documentación con el IDE y el tutorial de Java para hilos (y también con Google). Verificaré las especificaciones de la API en el futuro. Ese crítico "... nunca es legal empezar más de una vez ..." no está en las otras lecturas.
Será el

@coobird, si asigno el nombre del objeto del hilo anterior a un nuevo Thread (), después de que el hilo anterior haya terminado, ¿el hilo antiguo se recolectará como basura (es decir, se recicla automáticamente o debe hacerse explícitamente)?
snapfractalpop

Se recolectará como basura, siempre que el hilo ya no se esté ejecutando.
Vuelo

1
Esta respuesta está un poco desactualizada. Si un programa Java moderno necesita realizar una tarea más de una vez, no debe crear una nueva Threadcada vez. En su lugar, debería enviar la tarea a un grupo de subprocesos (por ejemplo, java.util.concurrent.ThreadPoolExecutor)
Solomon Slow

13

Exactamente correcto. De la documentación :

Nunca es legal iniciar un hilo más de una vez. En particular, es posible que un hilo no se reinicie una vez que haya completado la ejecución.

En términos de lo que puede hacer para el cálculo repetido, parece que podría usar el método invokeLater de SwingUtilities . Ya está experimentando con llamadas run()directamente, lo que significa que ya está pensando en usar un en Runnablelugar de un raw Thread. Intente usar el invokeLatermétodo solo en la Runnabletarea y vea si eso se ajusta un poco mejor a su patrón mental.

Aquí está el ejemplo de la documentación:

 Runnable doHelloWorld = new Runnable() {
     public void run() {
         // Put your UI update computations in here.
         // BTW - remember to restrict Swing calls to the AWT Event thread.
         System.out.println("Hello World on " + Thread.currentThread());
     }
 };

 SwingUtilities.invokeLater(doHelloWorld);
 System.out.println("This might well be displayed before the other message.");

Si reemplaza esa printlnllamada con su cálculo, podría ser exactamente lo que necesita.

EDITAR: siguiendo el comentario, no había notado la etiqueta de Android en la publicación original. El equivalente a invokeLater en el trabajo de Android es Handler.post(Runnable). De su javadoc:

/**
 * Causes the Runnable r to be added to the message queue.
 * The runnable will be run on the thread to which this handler is
 * attached.
 *
 * @param r The Runnable that will be executed.
 *
 * @return Returns true if the Runnable was successfully placed in to the
 *         message queue.  Returns false on failure, usually because the
 *         looper processing the message queue is exiting.
 */

Por lo tanto, en el mundo de Android, puede usar el mismo ejemplo que el anterior, reemplazando el Swingutilities.invokeLaterpor la publicación correspondiente a un Handler.


El OP está preguntando sobre subprocesos en Android, que no incluye SwingUtilities.
Austyn Mahoney

@Austyn, tienes razón. Agregué los comentarios sobre Handler.post () para ilustrar el código paralelo de Android.
Bob Cross

1
Otra forma, si solo está intentando actualizar su interfaz de usuario, es usar RunOnUIThread(Runnable)o en View.post(Runnable)lugar de crear su propio controlador. Estos ejecutarán el ejecutable en el hilo principal, lo que le permitirá actualizar la interfaz de usuario.
Austyn Mahoney

3

La respuesta recién llegada cubre por qué no debería hacer lo que está haciendo. Aquí hay algunas opciones para resolver su problema real.

Este hilo en particular está haciendo algunos cálculos en segundo plano, si no lo hago en el hilo, entonces se hace en el hilo de la interfaz de usuario y el usuario tiene una espera irrazonablemente larga.

Vierta su propio hilo y úselo AsyncTask.

O crea un hilo nuevo cuando lo necesites.

O configure su hilo para operar fuera de una cola de trabajo (por ejemplo, LinkedBlockingQueue) en lugar de reiniciar el hilo.


3

No , no podemos iniciar Thread de nuevo, hacerlo arrojará runtimeException java.lang.IllegalThreadStateException. >

La razón es que una vez que Thread ejecuta el método run (), entra en estado muerto.

Tomemos un ejemplo: pensar en iniciar el hilo nuevamente y llamar al método start () en él (que internamente llamará al método run ()) para nosotros es algo así como pedirle al hombre muerto que se despierte y corra. Como, después de completar su vida, la persona pasa al estado muerto.

public class MyClass implements Runnable{

    @Override
    public void run() {
           System.out.println("in run() method, method completed.");
    }

    public static void main(String[] args) {
                  MyClass obj=new MyClass();            
        Thread thread1=new Thread(obj,"Thread-1");
        thread1.start();
        thread1.start(); //will throw java.lang.IllegalThreadStateException at runtime
    }

}

/ * SALIDA en el método run (), método completado. Excepción en el hilo "principal" java.lang.IllegalThreadStateException en java.lang.Thread.start (Fuente desconocida) * /

Mira esto


2

Lo que debe hacer es crear un Runnable y envolverlo con un nuevo Thread cada vez que desee ejecutar Runnable. Sería realmente feo hacerlo, pero puede envolver un hilo con otro hilo para ejecutar el código nuevamente, pero solo haga esto si realmente tiene que hacerlo.


cualquier snipet, como envolver?
Vinay

1

Es como dijiste, un hilo no se puede iniciar más de una vez.

Directamente de la boca del caballo: Java API Spec

Nunca es legal iniciar un hilo más de una vez. En particular, es posible que un hilo no se reinicie una vez que haya completado la ejecución.

Si necesita volver a ejecutar lo que esté sucediendo en su hilo, tendrá que crear un nuevo hilo y ejecutarlo.


0

Reutilizar un hilo es una acción ilegal en la API de Java. Sin embargo, puede envolverlo en un implemento ejecutable y volver a ejecutar esa instancia nuevamente.


0

Sí, no podemos empezar a ejecutar el hilo. Lanzará IllegalThreadStateException en tiempo de ejecución, si el hilo ya se inició.

¿Qué sucede si realmente necesita iniciar el hilo? Opción 1) Si un hilo necesita ejecutarse más de una vez, entonces uno debe crear una nueva instancia del hilo y llamar a iniciar en él.


0

¿Se puede iniciar un hilo solo una vez?

Si. Puede iniciarlo exactamente una vez.

Si es así, ¿qué hago si quiero ejecutar el hilo de nuevo? Este hilo en particular está haciendo algunos cálculos en segundo plano, si no lo hago en el hilo, entonces se hace en el hilo de la interfaz de usuario y el usuario tiene un error irrazonable. larga espera.

No ejecutes el de Threadnuevo. En su lugar, cree Runnable y publíquelo en Handler of HandlerThread . Puede enviar varios Runnableobjetos. Si quiere devolver los datos a la interfaz de usuario de rosca, con-en su Runnable run()método, publicar Messageen Handlerla interfaz de usuario de rosca y el proceso dehandleMessage

Consulte esta publicación para obtener un código de ejemplo:

Android: brindis en un hilo


0

No sé si es una buena práctica, pero cuando dejo que se llame a run () dentro del método run (), no arroja ningún error y en realidad hace exactamente lo que quería.

Sé que no está comenzando un hilo de nuevo, pero tal vez esto sea útil para ti.

public void run() {

    LifeCycleComponent lifeCycleComponent = new LifeCycleComponent();

    try {
        NetworkState firstState = lifeCycleComponent.getCurrentNetworkState();
        Thread.sleep(5000);
        if (firstState != lifeCycleComponent.getCurrentNetworkState()) {
            System.out.println("{There was a NetworkState change!}");
            run();
        } else {
            run();
        }
    } catch (SocketException | InterruptedException e) {
        e.printStackTrace();
    }
}

public static void main(String[] args) {
    Thread checkingNetworkStates = new Thread(new LifeCycleComponent());
    checkingNetworkStates.start();
}

Espero que esto ayude, aunque sea un poco.

Salud


-1

Sería realmente feo hacerlo, pero puede envolver un hilo con otro hilo para ejecutar el código nuevamente, pero solo haga esto si realmente tiene que hacerlo.

Tuve que arreglar una fuga de recursos que fue causada por un programador que creó un Thread pero en lugar de iniciarlo () llamó directamente al método run (). Así que evítelo, a menos que realmente sepa qué efectos secundarios causa.


Pero la sugerencia fue no llamar run()directamente, solo incrustar un Runnable en un Thread y presumiblemente invocarlo start().
H2ONaCl

@ H2ONaCl Si lees el texto que cité, la sugerencia fue envolver un hilo en un hilo. Es posible que no hayas leído la sugerencia original antes de editarla.
Torben
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.