Cosa significa questo codice join thread?


156

In questo codice, cosa significano i due join e break? t1.join()provoca t2l'arresto fino al t1termine?

Thread t1 = new Thread(new EventThread("e1"));
t1.start();
Thread t2 = new Thread(new EventThread("e2"));
t2.start();
while (true) {
   try {
      t1.join();
      t2.join();
      break;
   } catch (InterruptedException e) {
      e.printStackTrace();
   }
}


3
Dal momento che bloccherà e attenderà la fine del thread, perché hai usato il ciclo while?
Mehdi,

@MahdiElMasaoudi, suppongo, per continuare ad aspettare anche se il thread è interrotto? Probabilmente non è un ottimo modo per farlo
forresthopkinsa

Ricorda di accettare una risposta qui se è stata utile.
Grigio

Come accennato, non è necessario il while(true)per chiamare il joinmetodo.
Chaklader Asfak Arefe,

Risposte:


311

Cosa significa questo codice join thread?

Per citare dal Thread.join()metodo javadocs :

join() Aspetta che questa discussione muoia.

C'è un thread che esegue il tuo codice di esempio che è probabilmente il thread principale .

  1. Il thread principale crea e avvia i thread t1e t2. I due thread iniziano a funzionare in parallelo.
  2. Il thread principale chiama t1.join()per attendere il t1termine del thread.
  3. Il t1thread viene completato e il t1.join()metodo ritorna nel thread principale. Si noti che t1potrebbe essere già terminato prima join()che venga effettuata la chiamata, nel qual caso la join()chiamata tornerà immediatamente.
  4. Il thread principale chiama t2.join()per attendere il t2termine del thread.
  5. Il t2thread viene completato (o potrebbe essere stato completato prima del t1thread) e il t2.join()metodo ritorna nel thread principale.

È importante capire che i thread t1e t2sono stati eseguiti in parallelo ma il thread principale che li ha avviati deve attendere che finiscano prima di poter continuare. Questo è uno schema comune. Inoltre, t1e / o t2potrebbe essere terminato prima che il thread principale join()li richiami . In tal caso join(), non attenderà ma tornerà immediatamente.

t1.join() significa che t2 si arresta fino a quando t1 termina?

No. Il thread principale che sta chiamando t1.join()si interromperà e attenderà il completamento del t1thread. Il t2filo viene eseguito in parallelo e non è influenzato dalla t1o la t1.join()chiamata affatto.

In termini di try / catch, i join()tiri InterruptedExceptionsignificano che il thread principale che sta chiamando join()può essere interrotto da un altro thread.

while (true) {

Avere i join in un whileciclo è uno schema strano. In genere si esegue il primo join e quindi il secondo join gestendo in modo InterruptedExceptionappropriato in ciascun caso. Non c'è bisogno di metterli in un ciclo.


24
+1 Questo è uno schema molto strano e probabilmente può essere rimosso.
m0skit0,

3
Se t1 finisce prima, quindi t2 per finire. Sembra un processo sequenziale. Prima finisce un thread, poi l'altro. qual è il punto di thread multipli?
user697911

9
Perché il t1e t2può funzionare in parallelo. È solo che mainentrambi hanno bisogno di finire prima che possa continuare. Questo è un tipico schema @ user697911.
Grigio

3
Il whileloop è lì perché (immagino) vuole riprovare le join()chiamate se una viene interrotta? Certamente non lo scriverei in questo modo @ user697911.
Grigio

5
Il loop è lì per garantire che entrambi t1e t2finire. Vale a dire. se t1lancia il InterruptedException, tornerà indietro e aspetterà t2. Un'alternativa è attendere entrambi i thread in ciascuno dei loro Try-Catch, in modo da poter evitare il loop. Inoltre, a seconda di EventThreadciò, può avere senso farlo in questo modo, poiché stiamo eseguendo 2 thread, non uno.
Michael Bisbjerg,

68

Questa è una delle domande preferite per l'intervista a Java .

Thread t1 = new Thread(new EventThread("e1"));
t1.start();
Thread e2 = new Thread(new EventThread("e2"));
t2.start();

while (true) {
    try {
        t1.join(); // 1
        t2.join(); // 2  These lines (1,2) are in in public static void main
        break;
    }
}

t1.join()significa che t1 dice qualcosa come " Voglio finire prima ". Lo stesso vale per t2. Non importa chi ha iniziato t1o t2discussione (in questo caso il mainmetodo), principale attenderà fino a quando t1e t2terminare il loro compito.

Tuttavia, un punto importante da annotare t1e t2loro stessi possono funzionare in parallelo indipendentemente dalla sequenza di chiamate di join su t1e t2. È il main/daemonthread che deve aspettare .


3
Buon esempio. Informazioni su "can run in parallel": E allora? È importante che il thread principale attenda PRIMA per t1 e POI per t2. Non importa cosa stiano facendo t1 o t2 (dal punto di vista della discussione principale)
Alex

1
Hai citato il thread "main / daemon". Il principale lo capisco, ma il demone non ha nulla a che fare con esso. Il thread principale è non-demone.
Grigio,

1
t1.join(); t2.join();non consentirà al thread che esegue i join di continuare fino a quando entrambi i thread non sono terminati. In assenza di codice molto insolito altrove, l'ordine dei join non ha importanza.
David Schwartz,

Quindi t2.join () verrà chiamato solo quando t1 avrà terminato?
Leo Droidcoder,

In altre parole, se vogliamo "serializzare" l'esecuzione dei thread t1 e t2, dobbiamo posizionare t1.join () subito dopo t1.start () poiché il thread principale ha iniziato t1 (e t2 in seguito) e ovviamente rimuoverlo da prova a prendere. Ovviamente, così facendo, la conseguenza sarà una perdita di parallelismo.
dobrivoje,

47

join()significa attendere il completamento di un thread. Questo è un metodo di blocco. Il thread principale (quello che esegue l'operazione join()) attenderà sulla t1.join()riga fino al t1termine del suo lavoro e quindi farà lo stesso per t2.join().


29

Un'immagine vale più di mille parole.

    Main thread-->----->--->-->--block##########continue--->---->
                 \                 |               |
sub thread start()\                | join()        |
                   \               |               |
                    ---sub thread----->--->--->--finish    

Spero di essere utile, per maggiori dettagli clicca qui


3
Chiaro e preciso
dobrivoje,

10

Quando il thread tA chiama tB.join (), le sue cause non solo attendono che tB muoia o tA venga interrotto da solo, ma creano una relazione accidentale prima dell'ultima istruzione in tB e dell'istruzione successiva dopo tB.join () nel thread tA.

Tutte le azioni in un thread si verificano prima che qualsiasi altro thread ritorni correttamente da un join () su quel thread.

Significa programma

class App {
    // shared, not synchronized variable = bad practice
    static int sharedVar = 0;
    public static void main(String[] args) throws Exception {
        Thread threadB = new Thread(() -> {sharedVar = 1;});
        threadB.start();
        threadB.join();

        while (true) 
            System.out.print(sharedVar);
    }
}

Stampa sempre

>> 1111111111111111111111111 ...

Ma programma

class App {
    // shared, not synchronized variable = bad practice
    static int sharedVar = 0;
    public static void main(String[] args) throws Exception {
        Thread threadB = new Thread(() -> {sharedVar = 1;});
        threadB.start();
        // threadB.join();  COMMENT JOIN

        while (true)
            System.out.print(sharedVar);
    }
}

Può stampare non solo

>> 0000000000 ... 000000111111111111111111111111 ...

Ma

>> 00000000000000000000000000000000000000000000 ... 

Sempre solo "0".

Poiché il modello di memoria Java non richiede il "trasferimento" del nuovo valore di "sharedVar" dal thread B al thread principale senza relazione heppens-before (inizio thread, thread thread, utilizzo della parola chiave "sincronizzata", utilizzo delle variabili AtomicXXX, ecc.).


5

In poche parole:
t1.join()ritorna dopo aver t1completato.
Non fa nulla per il thread t1, tranne aspettare che finisca.
Naturalmente, il codice seguente t1.join()verrà eseguito solo dopo i t1.join()ritorni.


1
verrà eseguito solo dopo che t1.join () restituisce +1
mohsen.nour

3

Dalla pagina della documentazione di Oracle su Joins

Il joinmetodo consente a un thread di attendere il completamento di un altro.

Se t1 è un Threadoggetto il cui thread è attualmente in esecuzione,

t1.join() : causes the current thread to pause execution until t1's thread terminates.

Se t2 è un Threadoggetto il cui thread è attualmente in esecuzione,

t2.join(); causes the current thread to pause execution until t2's thread terminates.

joinL'API è un'API di basso livello, che è stata introdotta nelle versioni precedenti di java. Molte cose sono state cambiate in un periodo di tempo (specialmente con la versione jdk 1.5) sul fronte della concorrenza.

Puoi ottenere lo stesso risultato con l'API java.util.concurrent. Alcuni esempi sono

  1. Utilizzando invokeAll onExecutorService
  2. Utilizzando CountDownLatch
  3. Uso di ForkJoinPool o newWorkStealingPool di Executors(da java 8)

Fare riferimento alle relative domande SE:

attendere che tutti i thread finiscano il loro lavoro in Java


1

Per me, il comportamento di Join () era sempre confuso perché cercavo di ricordare chi aspetterebbe chi. Non cercare di ricordarlo in quel modo.

Al di sotto, è puro meccanismo wait () e notify ().

Sappiamo tutti che, quando chiamiamo wait () su qualsiasi oggetto (t1), l'oggetto chiamante (principale) viene inviato nella sala d'attesa (stato bloccato).

Qui, il thread principale sta chiamando join () che è wait () sotto le copertine. Quindi il thread principale attenderà fino alla sua notifica. La notifica viene data da t1 al termine dell'esecuzione (completamento del thread).

Dopo aver ricevuto la notifica, main esce dalla sala d'attesa e procede alla sua esecuzione.


0

Spero che sia d'aiuto!

package join;

public class ThreadJoinApp {

    Thread th = new Thread("Thread 1") {
        public void run() {
            System.out.println("Current thread execution - " + Thread.currentThread().getName());
            for (int i = 0; i < 10; i++) {
                System.out.println("Current thread execution - " + Thread.currentThread().getName() + " at index - " + i);
            }
        }
    };

    Thread th2 = new Thread("Thread 2") {
        public void run() {
            System.out.println("Current thread execution - " + Thread.currentThread().getName());

            //Thread 2 waits until the thread 1 successfully completes.
            try {
            th.join();
            } catch( InterruptedException ex) {
                System.out.println("Exception has been caught");
            }

            for (int i = 0; i < 10; i++) {
                System.out.println("Current thread execution - " + Thread.currentThread().getName() + " at index - " + i);
            }
        }
    };

    public static void main(String[] args) {
        ThreadJoinApp threadJoinApp = new ThreadJoinApp();
        threadJoinApp.th.start();
        threadJoinApp.th2.start();
    }

    //Happy coding -- Parthasarathy S
}

-3

diciamo che il nostro thread principale avvia i thread t1 e t2. Ora, quando viene chiamato t1.join (), il thread principale si sospende fino a quando il thread t1 non muore e quindi riprende. Allo stesso modo, quando t2.join () viene eseguito, il thread principale si sospende nuovamente fino a quando il thread t2 muore e quindi riprende.

Quindi, funziona così.

Inoltre, il ciclo while non era davvero necessario qui.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.