studio programacion móviles hilos ejemplo desarrollo curso cronometro contador con aplicaciones java multithreading

java - programacion - ¿Cómo saber si otros hilos han terminado?



manual de programacion android pdf (11)

Tengo un objeto con un método llamado StartDownload() , que inicia tres hilos.

¿Cómo recibo una notificación cuando cada hilo ha terminado de ejecutarse?

¿Hay alguna manera de saber si uno (o todos) del hilo ha terminado o todavía se está ejecutando?


¿Quieres esperar a que terminen? Si es así, usa el método de unión.

También está la propiedad isAlive si solo quieres comprobarlo.


Aquí hay una solución que es simple, corta, fácil de entender y funciona perfectamente para mí. Necesitaba dibujar a la pantalla cuando termina otro hilo; pero no pudo porque el hilo principal tiene el control de la pantalla. Asi que:

(1) boolean end1 = false; variable global: boolean end1 = false; El hilo lo establece en verdadero cuando termina. Esto se recoge en el hilo principal mediante el bucle "postDelayed", donde se responde.

(2) Mi hilo contiene:

void myThread() { end1 = false; new CountDownTimer(((60000, 1000) { // milliseconds for onFinish, onTick public void onFinish() { // do stuff here once at end of time. end1 = true; // signal that the thread has ended. } public void onTick(long millisUntilFinished) { // do stuff here repeatedly. } }.start(); }

(3) Afortunadamente, "postDelayed" se ejecuta en el hilo principal, por lo que es donde se comprueba el otro hilo una vez por segundo. Cuando termina el otro hilo, puede comenzar lo que queramos hacer a continuación.

Handler h1 = new Handler(); private void checkThread() { h1.postDelayed(new Runnable() { public void run() { if (end1) // resond to the second thread ending here. else h1.postDelayed(this, 1000); } }, 1000); }

(4) Finalmente, comience todo en algún lugar de su código llamando al:

void startThread() { myThread(); checkThread(); }


Hay varias formas en que puede hacer esto:

  1. Utilice Thread.join() en su hilo principal para esperar de forma bloqueada a que cada subproceso se complete, o
  2. Compruebe Thread.isAlive() en una encuesta, generalmente desaconsejado, para esperar hasta que cada subproceso se haya completado, o
  3. Poco ortodoxo, para cada Subproceso en cuestión, llame a setUncaughtExceptionHandler para llamar a un método en su objeto, y programe cada Subproceso para lanzar una Excepción no detectada cuando se complete, o
  4. Use bloqueos o sincronizadores o mecanismos de java.util.concurrent , o
  5. Más ortodoxo, crea un oyente en tu hilo principal y luego programa cada uno de tus hilos para decirle al oyente que se han completado.

¿Cómo implementar Idea # 5? Bueno, una forma es crear primero una interfaz:

public interface ThreadCompleteListener { void notifyOfThreadComplete(final Thread thread); }

luego crea la siguiente clase:

public abstract class NotifyingThread extends Thread { private final Set<ThreadCompleteListener> listeners = new CopyOnWriteArraySet<ThreadCompleteListener>(); public final void addListener(final ThreadCompleteListener listener) { listeners.add(listener); } public final void removeListener(final ThreadCompleteListener listener) { listeners.remove(listener); } private final void notifyListeners() { for (ThreadCompleteListener listener : listeners) { listener.notifyOfThreadComplete(this); } } @Override public final void run() { try { doRun(); } finally { notifyListeners(); } } public abstract void doRun(); }

y luego cada uno de sus Threads extenderá NotifyingThread y en lugar de implementar run() implementará doRun() . Por lo tanto, cuando completen, automáticamente notificarán a cualquier persona que esté esperando una notificación.

Finalmente, en su clase principal, la que inicia todos los Threads (o al menos el objeto que espera la notificación), modifique esa clase para implement ThreadCompleteListener e inmediatamente después de crear cada Thread se agregue a la lista de oyentes:

NotifyingThread thread1 = new OneOfYourThreads(); thread1.addListener(this); // add ourselves as a listener thread1.start(); // Start the Thread

luego, a medida que sale cada Thread, su método notifyOfThreadComplete se invocará con la instancia de Thread que acaba de completarse (o se colgó).

Tenga en cuenta que sería mejor implements Runnable lugar de extends Thread para NotifyingThread ya que la extensión de Thread generalmente no se recomienda en el nuevo código. Pero estoy codificando tu pregunta. Si cambias la clase Runnable para implementar Runnable entonces debes cambiar parte del código que administra Threads, lo que es bastante sencillo de hacer.


Mira la documentación de Java para la clase Thread. Puede verificar el estado del hilo. Si coloca los tres hilos en las variables miembro, entonces los tres hilos pueden leer los estados de los demás.

Tienes que ser un poco cuidadoso, porque puedes causar condiciones de carrera entre los hilos. Solo trata de evitar una lógica complicada basada en el estado de los otros hilos. Definitivamente evitar múltiples hilos escribiendo en las mismas variables.


Muchas cosas han cambiado en los últimos 6 años en el frente de multi-threading.

En lugar de usar join() y bloquear API, puede usar

1. invokeAll() ExecutorService invokeAll()

Ejecuta las tareas dadas, devolviendo una lista de futuros que mantienen su estado y resultados cuando todo se completa.

2. CountDownLatch

Un asistente de sincronización que permite que uno o más subprocesos esperen hasta que se complete un conjunto de operaciones en otros subprocesos.

Un CountDownLatch se inicializa con un conteo dado. El bloque de métodos de espera hasta que el recuento actual llega a cero debido a las invocaciones del método countDown() , después del cual se liberan todos los subprocesos en espera y las invocaciones posteriores de espera vuelven inmediatamente. Este es un fenómeno de una sola vez: el recuento no se puede restablecer. Si necesita una versión que restablece el recuento, considere usar un CyclicBarrier.

3. ForkJoinPool o newWorkStealingPool() en los Executors es de otra manera

4. Examine todas las tareas Future de submit en ExecutorService y verifique el estado con la llamada de bloqueo get() en el objeto Future

Eche un vistazo a las preguntas relacionadas SE:

¿Cómo esperar un hilo que genere su propio hilo?

Ejecutores: ¿Cómo esperar sincrónicamente hasta que todas las tareas hayan finalizado si las tareas se crean recursivamente?


Puede interrogar la instancia de subproceso con getState () que devuelve una instancia de enumeración Thread.State con uno de los siguientes valores:

* NEW A thread that has not yet started is in this state. * RUNNABLE A thread executing in the Java virtual machine is in this state. * BLOCKED A thread that is blocked waiting for a monitor lock is in this state. * WAITING A thread that is waiting indefinitely for another thread to perform a particular action is in this state. * TIMED_WAITING A thread that is waiting for another thread to perform an action for up to a specified waiting time is in this state. * TERMINATED A thread that has exited is in this state.

Sin embargo, creo que sería un mejor diseño tener un hilo maestro que espere que los 3 niños terminen, el maestro continuará la ejecución cuando los otros 3 hayan terminado.


Sugeriría mirar el javadoc para la clase Thread .

Tienes múltiples mecanismos para la manipulación de hilos.

  • Su hilo principal podría join() los tres hilos en serie, y luego no procedería hasta que los tres hayan terminado.

  • Encuestar el estado del hilo de los hilos engendrados a intervalos.

  • Coloque todos los hilos generados en un ThreadGroup separado y ThreadGroup el activeCount() en el ThreadGroup y espere que llegue a 0.

  • Configure una devolución de llamada personalizada o un tipo de interfaz de escucha para la comunicación entre hilos.

Estoy seguro de que todavía faltan muchas otras formas.


También podría usar el objeto Executors para crear un grupo de subprocesos de ExecutorService . A continuación, utilice el método invokeAll para ejecutar cada uno de sus subprocesos y recuperar futuros. Esto se bloqueará hasta que todos hayan terminado la ejecución. Su otra opción sería ejecutar cada uno usando el grupo y luego llamar a awaitTermination para bloquear hasta que el grupo termine de ejecutarse. Solo asegúrese de llamar a shutdown () cuando termine de agregar tareas.


También puede usar SwingWorker, que tiene soporte de cambio de propiedad incorporado. Consulte addPropertyChangeListener() o el método get() para un ejemplo de detector de cambio de estado.


Realmente debería preferir una solución que use java.util.concurrent . Encuentra y lee a Josh Bloch y / o Brian Goetz sobre el tema.

Si no está utilizando java.util.concurrent.* Y se responsabiliza de usar Threads directamente, entonces probablemente debería usar join() para saber cuándo se realiza un thread. Aquí hay un mecanismo de devolución de llamada súper simple. Primero amplíe la interfaz Runnable para tener una devolución de llamada:

public interface CallbackRunnable extends Runnable { public void callback(); }

Luego crea un ejecutor que ejecutará tu ejecutable y te devolverá la llamada cuando esté listo.

public class CallbackExecutor implements Executor { @Override public void execute(final Runnable r) { final Thread runner = new Thread(r); runner.start(); if ( r instanceof CallbackRunnable ) { // create a thread to perform the callback Thread callerbacker = new Thread(new Runnable() { @Override public void run() { try { // block until the running thread is done runner.join(); ((CallbackRunnable)r).callback(); } catch ( InterruptedException e ) { // someone doesn''t want us running. ok, maybe we give up. } } }); callerbacker.start(); } } }

El otro tipo de cosas obvias para agregar a su interfaz CallbackRunnable es un medio para manejar cualquier excepción, por lo tanto, quizás coloque un public void uncaughtException(Throwable e); línea allí y en su ejecutor, instale un Thread.UncaughtExceptionHandler para enviarlo a ese método de interfaz.

Pero hacer todo eso realmente comienza a oler como java.util.concurrent.Callable . Realmente debería considerar usar java.util.concurrent si su proyecto lo permite.


Solución usando CyclicBarrier

public class Downloader { private CyclicBarrier barrier; private final static int NUMBER_OF_DOWNLOADING_THREADS; private DownloadingThread extends Thread { private final String url; public DownloadingThread(String url) { super(); this.url = url; } @Override public void run() { barrier.await(); // label1 download(url); barrier.await(); // label2 } } public void startDownload() { // plus one for the main thread of execution barrier = new CyclicBarrier(NUMBER_OF_DOWNLOADING_THREADS + 1); // label0 for (int i = 0; i < NUMBER_OF_DOWNLOADING_THREADS; i++) { new DownloadingThread("http://www.flickr.com/someUser/pic" + i + ".jpg").start(); } barrier.await(); // label3 displayMessage("Please wait..."); barrier.await(); // label4 displayMessage("Finished"); } }

label0 : la barrera cíclica se crea con el número de partes igual al número de subprocesos de ejecución más uno para el subproceso principal de ejecución (en el que se está ejecutando startDownload ())

label 1 - n-th DownloadingThread ingresa a la sala de espera

label 3 - NUMBER_OF_DOWNLOADING_THREADS ha ingresado a la sala de espera. El hilo principal de ejecución los libera para comenzar a hacer sus trabajos de descarga más o menos al mismo tiempo

label 4 - el hilo principal de ejecución entra a la sala de espera. Esta es la parte más "complicada" del código para entender. No importa qué hilo ingresará a la sala de espera por segunda vez. Es importante que el hilo que ingrese a la sala por última vez asegure que todos los demás subprocesos de descarga hayan terminado sus trabajos de descarga.

label 2 - n-th DownloadingThread ha terminado su trabajo de descarga y entra a la sala de espera. Si es el último, es decir, ya lo han ingresado NUMBER_OF_DOWNLOADING_THREADS, incluido el hilo principal de ejecución, el hilo principal continuará su ejecución solo cuando todos los demás hilos hayan terminado de descargarse.