2009-08-01 18 views
73

El siguiente código conduce a java.lang.IllegalThreadStateException: Thread already started cuando llamé al start() método segunda vez en el programa.¿Es legal llamar al método de inicio dos veces en el mismo hilo?

updateUI.join();  

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

esto sucede, el tiempo segundoupdateUI.start() se llama. Lo he revisado varias veces y se ha llamado al hilo y se ejecuta completamente antes de llegar al updateUI.start().

Llamar a updateUI.run() evita el error pero hace que el subproceso se ejecute en el subproceso de IU (el subproceso de llamada, como se menciona en otras publicaciones en SO), que no es lo que quiero.

¿Puede un hilo ser comenzado sólo una vez? Si es así, ¿qué hago si quiero ejecutar el hilo nuevamente? Este hilo en particular está haciendo algunos cálculos en el fondo, si no lo hago en el hilo de lo que está hecho en el hilo de la interfaz de usuario y el usuario tiene una espera irracionalmente larga.

+9

Por qué ¿No acabas de leer el javadoc? Describe claramente el contrato. –

Respuesta

97

Desde el Java API Specification para el método Thread.start:

Nunca es legal para iniciar un hilo más de una vez. En particular, un hilo no se puede reiniciar una vez que ha completado la ejecución.

Además:

Lanza:
IllegalThreadStateException - si el hilo ya se ha iniciado.

Así que sí, un Thread solo se puede iniciar una vez.

Si es así, ¿qué hago si quiero ejecutar el hilo de nuevo?

Si un Thread deba llevarse a cabo más de una vez, entonces uno debe hacer una nueva instancia de la Thread y llame start en él.

+0

Gracias. Revisé la documentación con el IDE y el tutorial de Java para hilos (y google también). Comprobaré las especificaciones API en el futuro. Ese crítico "... nunca es legal comenzar más de una vez ..." no está en las otras lecturas. – Will

+0

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

+0

Se recolectará basura, siempre que el subproceso ya no se esté ejecutando. – flygoing

1

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

Directamente desde la boca del caballo: Java API Spec

Nunca es legal para iniciar un hilo más de una vez. En particular, un hilo no se puede reiniciar una vez que ha completado la ejecución.

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

3

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

Este hilo en particular está haciendo un cálculo en el fondo, si no lo hago en el hilo de lo que ha hecho en el hilo de interfaz de usuario y el usuario tiene un irrazonablemente larga espera.

Vuelca tu propio hilo y usa AsyncTask.

O cree un hilo nuevo cuando lo necesite.

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

13

Exactamente a la derecha. From the documentation:

Nunca es legal para iniciar un hilo más de una vez. En particular, un hilo no se puede reiniciar una vez que ha completado la ejecución.

En términos de lo que puede hacer para el cálculo repetido, parece que podría usar SwingUtilities invokeLater method. Usted ya está experimentando con llamar al run() directamente, lo que significa que ya está pensando en usar un Runnable en lugar de un Thread en bruto. Intente utilizar el método invokeLater en la tarea Runnable 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 que println llamada con su cálculo, que sólo podría ser exactamente lo que necesita.

EDITAR: al seguir con 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). Desde 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 Android, se puede utilizar el mismo ejemplo anterior, sustituyendo el Swingutilities.invokeLater con el puesto adecuado a un Handler.

+0

El OP pregunta por el enhebrado en Android, que no incluye SwingUtilities. –

+0

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

+1

Otra forma si solo intenta actualizar su UI es usar 'RunOnUIThread (Runnable)' o 'View.post (Runnable)' en lugar de crear su propio controlador. Estos ejecutarán el runnable en el hilo principal permitiéndole actualizar la interfaz de usuario. –

2

Lo que debe hacer es crear un Runnable y envolverlo con un nuevo subproceso cada vez que desee ejecutar Runnable. Sería realmente feo, pero puedes Ajustar un hilo con otro hilo para ejecutar el código de nuevo, pero solo esto es lo que realmente debes hacer.

+0

cualquier snipet, cómo envolver? – Vinay

+1

@Vinay más simple es 'new Thread (ejecutable) .start();' –

-1

Sería realmente feo hacerlo pero puede Enrollar un hilo con otro hilo para ejecutar el código de nuevo, pero solo esto es lo que realmente debe hacer.

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

+0

Pero la sugerencia no era llamar 'run()' directamente, solo para incrustar un Runnable en un Thread y presumiblemente invocar 'start()'. – H2ONaCl

+0

@ H2ONaCl Si leyó 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

0

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

2

Sin, no podemos empezar de nuevo Tema, al hacerlo, tirar RuntimeException java.lang.IllegalThreadStateException. >

El motivo es que una vez que el método run() se ejecuta con el subproceso, entra en estado muerto.

Tomemos un ejemplo- pensando en comenzar hilo nuevo y el método start() en él (que internamente se va a llamar al método run()) para que nos llama es lo que algunos como pedirle a hombre muerto para despertar y correr. Como, después de completar su vida, la persona queda en 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 
    } 

} 

/* OUTPUT en método run(), el método de completado. Excepción en hilo java.lang.IllegalThreadStateException "principal" en java.lang.Thread.start (origen desconocido) */

check this

0

Sí No podemos empezar ya se está ejecutando hilo. Lanzará IllegalThreadStateException en tiempo de ejecución, si el hilo ya se inició.

¿Qué pasa si realmente necesita iniciar el hilo: Opción 1) Si un subproceso necesita ejecutarse más de una vez, entonces uno debe hacer una nueva instancia del subproceso y ejecutar la llamada en él.

0

¿Se puede iniciar un hilo solamente una vez?

Sí. Puedes comenzarlo 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 el fondo, si no lo hago en el hilo de lo que se hace en el hilo de la interfaz de usuario y el usuario tiene una espera irracionalmente larga.

No vuelva a ejecutar Thread. En su lugar, cree Runnable y publíquelo en Handler de HandlerThread. Puede enviar múltiples objetos Runnable. Si desea enviar datos a la interfaz de usuario de rosca, con en su método de Runnablerun(), publicar un Message en Handler de hilo de interfaz de usuario y el proceso handleMessage

se refieren a este puesto de ejemplo de código:

Android: Toast in a thread

Cuestiones relacionadas