La méthode Thread.join () en Java

1. Vue d'ensemble

Dans ce didacticiel, nous aborderons les différentes méthodes join () de la classe Thread . Nous allons entrer dans les détails de ces méthodes et quelques exemples de code.

Comme les méthodes wait () et notify () , join () est un autre mécanisme de synchronisation inter-thread.

Vous pouvez jeter un coup d'œil à ce didacticiel pour en savoir plus sur wait () et notify () .

2. Le Thread.join () Méthode

La méthode de jointure est définie dans la classe Thread :

public final void join () jette une exception InterruptedException

Attend que ce fil meure.

Lorsque nous invoquons la méthode join () sur un thread, le thread appelant passe dans un état d'attente. Il reste dans un état d'attente jusqu'à ce que le thread référencé se termine.

Nous pouvons voir ce comportement dans le code suivant:

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()); } 

Nous devrions nous attendre à des résultats similaires aux suivants lors de l'exécution du code:

INFO: Thread Created INFO: Invoking join INFO: Thread Thread-1 started INFO: Thread Thread-1 exiting INFO: Returned from join

La méthode join () peut également retourner si le thread référencé a été interrompu . Dans ce cas, la méthode lève une InterruptedException .

Enfin, si le thread référencé était déjà terminé ou n'a pas été démarré, l'appel à la méthode join () retourne immédiatement .

Thread t1 = new SampleThread(0); t1.join(); //returns immediately

3. Méthodes Thread.join () avec timeout

La méthode join () continuera à attendre si le thread référencé est bloqué ou prend trop de temps à traiter. Cela peut devenir un problème car le thread appelant deviendra non réactif. Pour gérer ces situations, nous utilisons des versions surchargées de la méthode join () qui nous permettent de spécifier un délai d'expiration.

Il existe deux versions chronométrées qui surchargent la méthode join () :

«La jointure vide finale publique ( millisecondes ) lève une exception InterruptedException

Attend au plus millis millisecondes pour que ce thread meure. Un délai d'expiration de 0 signifie attendre indéfiniment. "

" Jointure vide finale publique (long millis, intnanos ) lance InterruptedException

Attend au plus quelques millis millisecondes plus nanos nanosecondes pour que ce thread meure. »

Nous pouvons utiliser la jointure chronométrée () comme ci-dessous:

@Test public void givenStartedThread_whenTimedJoinCalled_waitsUntilTimedout() throws InterruptedException { Thread t3 = new SampleThread(10); t3.start(); t3.join(1000); assertTrue(t3.isAlive()); } 

Dans ce cas, le thread appelant attend environ 1 seconde que le thread t3 se termine. Si le thread t3 ne se termine pas dans cette période, la méthode join () renvoie le contrôle à la méthode appelante.

La jointure cadencée () dépend du système d'exploitation pour la synchronisation. Donc, nous ne pouvons pas supposer que join () attendra exactement aussi longtemps que spécifié.

4. Méthodes Thread.join () et synchronisation

En plus d'attendre la fin, l'appel de la méthode join () a un effet de synchronisation. join () crée une relation qui arrive avant:

"Toutes les actions d'un thread se produisent avant que tout autre thread ne retourne avec succès d'une jointure () sur ce thread.

Cela signifie que lorsqu'un thread t1 appelle t2.join (), alors toutes les modifications effectuées par t2 sont visibles dans t1 au retour. Cependant, si nous n'appelons pas join () ou n'utilisons pas d'autres mécanismes de synchronisation, nous n'avons aucune garantie que les changements dans l'autre thread seront visibles par le thread actuel même si l'autre thread est terminé.

Par conséquent, même si l' appel de la méthode join () à un thread dans l'état terminé retourne immédiatement, nous devons toujours l'appeler dans certaines situations.

Nous pouvons voir un exemple de code mal synchronisé ci-dessous:

SampleThread t4 = new SampleThread(10); t4.start(); // not guaranteed to stop even if t4 finishes. do { } while (t4.processingCount > 0);

Pour synchroniser correctement le code ci-dessus, nous pouvons ajouter t4.join () chronométré à l'intérieur de la boucle ou utiliser un autre mécanisme de synchronisation.

5. Conclusion

La méthode join () est très utile pour la synchronisation inter-thread. Dans cet article, nous avons discuté des méthodes join () et de leur comportement. Nous avons également examiné le code en utilisant la méthode join () .

Comme toujours, le code source complet peut être trouvé sur GitHub.