Il metodo Thread.join () in Java

1. Panoramica

In questo tutorial, discuteremo i diversi metodi join () nella classe Thread . Entreremo nei dettagli di questi metodi e in alcuni esempi di codice.

Come i metodi wait () e notify () , join () è un altro meccanismo di sincronizzazione tra thread.

Puoi dare una rapida occhiata a questo tutorial per saperne di più su wait () e notify () .

2. Il metodo Thread.join ()

Il metodo join è definito nella classe Thread :

public final void join () genera InterructedException

Aspetta che questo filo muoia.

Quando invochiamo il metodo join () su un thread, il thread chiamante entra in uno stato di attesa. Rimane in uno stato di attesa fino al termine del thread a cui si fa riferimento.

Possiamo vedere questo comportamento nel codice seguente:

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

Dovremmo aspettarci risultati simili ai seguenti durante l'esecuzione del codice:

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

Il metodo join () può anche restituire se il thread di riferimento è stato interrotto . In questo caso, il metodo genera un'InterruptException .

Infine, se il thread a cui si fa riferimento era già terminato o non è stato avviato, la chiamata al metodo join () ritorna immediatamente .

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

3. Metodi Thread.join () con timeout

Il metodo join () continuerà ad aspettare se il thread di riferimento è bloccato o impiega troppo tempo per essere elaborato. Questo può diventare un problema poiché il thread chiamante diventerà non rispondente. Per gestire queste situazioni, utilizziamo versioni sovraccaricate del metodo join () che ci consentono di specificare un periodo di timeout.

Esistono due versioni a tempo che sovraccaricano il metodo join () :

"Public final void join (long millis ) genera InterructedException

Attese al maggior Millis millisecondi per questo thread morire. Un timeout di 0 significa aspettare per sempre. "

"Public final void join (long millis, intnanos ) genera InterructedException

Attese al maggior Millis millisecondi inclusa nanos nanosecondi per questo thread morire.”

Possiamo usare il timed join () come di seguito:

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

In questo caso, il thread chiamante attende circa 1 secondo per il completamento del thread t3. Se il thread t3 non termina in questo periodo di tempo, il metodo join () restituisce il controllo al metodo chiamante.

Timed join () dipende dal sistema operativo per la temporizzazione. Quindi, non possiamo presumere che join () attenderà esattamente il tempo specificato.

4. Metodi Thread.join () e sincronizzazione

Oltre ad attendere fino al termine, la chiamata al metodo join () ha un effetto di sincronizzazione. join () crea una relazione accade prima:

"Tutte le azioni in un thread avvengono prima che qualsiasi altro thread ritorni con successo da un join () su quel thread."

Ciò significa che quando un thread t1 chiama t2.join (), tutte le modifiche apportate da t2 sono visibili in t1 al ritorno. Tuttavia, se non invochiamo join () o utilizziamo altri meccanismi di sincronizzazione, non abbiamo alcuna garanzia che le modifiche nell'altro thread saranno visibili al thread corrente anche se l'altro thread è stato completato.

Quindi, anche se la chiamata al metodo join () a un thread nello stato terminato ritorna immediatamente, dobbiamo comunque chiamarla in alcune situazioni.

Di seguito possiamo vedere un esempio di codice sincronizzato in modo improprio:

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

Per sincronizzare correttamente il codice sopra, possiamo aggiungere t4.join () temporizzato all'interno del ciclo o utilizzare qualche altro meccanismo di sincronizzazione.

5. conclusione

Il metodo join () è abbastanza utile per la sincronizzazione tra thread. In questo articolo, abbiamo discusso i metodi join () e il loro comportamento. Abbiamo anche esaminato il codice utilizzando il metodo join () .

Come sempre, il codice sorgente completo può essere trovato su GitHub.