1. Información general
En este tutorial, discutiremos los diferentes métodos join () en la clase Thread . Entraremos en los detalles de estos métodos y algunos ejemplos de código.
Al igual que los métodos wait () y notify () , join () es otro mecanismo de sincronización entre subprocesos.
Puede echar un vistazo rápido a este tutorial para leer más sobre wait () y notificar () .
2. El Thread.join () Método
El método de unión se define en la clase Thread :
public final void join () arroja InterruptedException
Espera a que muera este hilo.
Cuando invocamos el método join () en un hilo, el hilo que llama entra en un estado de espera. Permanece en un estado de espera hasta que termina el hilo referenciado.
Podemos ver este comportamiento en el siguiente código:
class SampleThread extends Thread { public int processingCount = 0; SampleThread(int processingCount) { this.processingCount = processingCount; LOGGER.info("Thread Created"); } @Override public void run() { LOGGER.info("Thread " + this.getName() + " started"); while (processingCount > 0) { try { Thread.sleep(1000); } catch (InterruptedException e) { LOGGER.info("Thread " + this.getName() + " interrupted"); } processingCount--; } LOGGER.info("Thread " + this.getName() + " exiting"); } } @Test public void givenStartedThread_whenJoinCalled_waitsTillCompletion() throws InterruptedException { Thread t2 = new SampleThread(1); t2.start(); LOGGER.info("Invoking join"); t2.join(); LOGGER.info("Returned from join"); assertFalse(t2.isAlive()); }
Deberíamos esperar resultados similares a los siguientes al ejecutar el código:
INFO: Thread Created INFO: Invoking join INFO: Thread Thread-1 started INFO: Thread Thread-1 exiting INFO: Returned from join
El método join () también puede regresar si se interrumpió el hilo al que se hace referencia . En este caso, el método arroja una InterruptedException .
Finalmente, si el hilo al que se hace referencia ya se terminó o no se ha iniciado, la llamada al método join () regresa inmediatamente .
Thread t1 = new SampleThread(0); t1.join(); //returns immediately
3. Métodos Thread.join () con tiempo de espera
El método join () seguirá esperando si el hilo al que se hace referencia está bloqueado o tarda demasiado en procesarse. Esto puede convertirse en un problema ya que el hilo de llamada dejará de responder. Para manejar estas situaciones, usamos versiones sobrecargadas del método join () que nos permiten especificar un período de tiempo de espera.
Hay dos versiones cronometradas que sobrecargan el método join () :
"La combinación vacía final pública ( milisegundos largos ) arroja una excepción InterruptedException
Espera en la mayoría de Millis milisegundos para este hilo para mueren. Un tiempo de espera de 0 significa esperar eternamente ".
"Unión vacía final pública (long millis, intnanos ) lanza InterruptedException
Espera en la mayoría de Millis milisegundos más nanos nanosegundos para este hilo para mueren “.
Podemos usar la combinación temporizada () como se muestra a continuación:
@Test public void givenStartedThread_whenTimedJoinCalled_waitsUntilTimedout() throws InterruptedException { Thread t3 = new SampleThread(10); t3.start(); t3.join(1000); assertTrue(t3.isAlive()); }
En este caso, el hilo de llamada espera aproximadamente 1 segundo para que termine el hilo t3. Si el hilo t3 no termina en este período de tiempo, el método join () devuelve el control al método de llamada.
La combinación temporizada () depende del sistema operativo para la sincronización. Por lo tanto, no podemos asumir que join () esperará exactamente el tiempo especificado.
4. Métodos y sincronización de Thread.join ()
Además de esperar hasta la terminación, la llamada al método join () tiene un efecto de sincronización. join () crea una relación sucede antes:
"Todas las acciones en un hilo suceden antes de que cualquier otro hilo regrese exitosamente de un join () en ese hilo".
Esto significa que cuando un subproceso t1 llama a t2.join (), todos los cambios realizados por t2 son visibles en t1 al regresar. Sin embargo, si no invocamos join () o usamos otros mecanismos de sincronización, no tenemos ninguna garantía de que los cambios en el otro hilo serán visibles para el hilo actual incluso si el otro hilo se ha completado.
Por lo tanto, aunque la llamada al método join () a un hilo en el estado terminado regresa inmediatamente, aún necesitamos llamarlo en algunas situaciones.
Podemos ver un ejemplo de código sincronizado incorrectamente a continuación:
SampleThread t4 = new SampleThread(10); t4.start(); // not guaranteed to stop even if t4 finishes. do { } while (t4.processingCount > 0);
Para sincronizar correctamente el código anterior, podemos agregar t4.join () temporizado dentro del bucle o usar algún otro mecanismo de sincronización.
5. Conclusión
El método join () es bastante útil para la sincronización entre subprocesos. En este artículo, discutimos los métodos join () y su comportamiento. También revisamos el código usando el método join () .
Como siempre, el código fuente completo se puede encontrar en GitHub.