El siguiente código conduce a java.lang.IllegalThreadStateException: Thread already started
cuando 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.
fuente
Respuestas:
De la especificación de la API de Java para el
Thread.start
método:Además:
Entonces sí,
Thread
solo se puede iniciar una vez.Si es
Thread
necesario ejecutar a más de una vez, entonces uno debe crear una nueva instancia deThread
e invocarlostart
.fuente
Thread
cada vez. En su lugar, debería enviar la tarea a un grupo de subprocesos (por ejemplo,java.util.concurrent.ThreadPoolExecutor
)Exactamente correcto. De la documentació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 enRunnable
lugar de un rawThread
. Intente usar elinvokeLater
método solo en laRunnable
tarea 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
println
llamada 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.invokeLater
por la publicación correspondiente a unHandler
.fuente
RunOnUIThread(Runnable)
o enView.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.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.
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.fuente
No , no podemos iniciar Thread de nuevo, hacerlo arrojará runtimeException java.lang.IllegalThreadStateException. >
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 } }
Mira esto
fuente
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.
fuente
Es como dijiste, un hilo no se puede iniciar más de una vez.
Directamente de la boca del caballo: Java API Spec
Si necesita volver a ejecutar lo que esté sucediendo en su hilo, tendrá que crear un nuevo hilo y ejecutarlo.
fuente
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.
fuente
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.
fuente
Si. Puede iniciarlo exactamente una vez.
No ejecutes el de
Thread
nuevo. En su lugar, cree Runnable y publíquelo en Handler of HandlerThread . Puede enviar variosRunnable
objetos. Si quiere devolver los datos a la interfaz de usuario de rosca, con-en suRunnable
run()
método, publicarMessage
enHandler
la 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
fuente
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
fuente
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.
fuente
run()
directamente, solo incrustar un Runnable en un Thread y presumiblemente invocarlostart()
.