3

Ich habe einen Code, wo 4 Threads zur gleichen Zeit ausgeführt werden. Ich möchte warten, bis alle diese 4 Threads fertig sind. Und erst danach, um den App-Flow fortzusetzen.ExecutorService shutdown() wartet nicht, bis alle Threads beendet sind

Ich habe versucht, zwei Ansätze:

  1. Thread#join() dieser Ansatz funktioniert wie erwartet. Der Code, der nach join() kommt, wird erst ausgeführt, nachdem alle Threads beendet sind.
  2. ExecutorService#shutdown(), ermöglicht diese Technik die Ausführung von Code, der nach shutdown() kommt, auch wenn nicht alle Threads beendet sind.

Codebeispiel:

ExecutorService service = Executors.newFixedThreadPool(cpuCoresNum); 

for (int i = 0; i < cpuCoresNum; i++) { 

    service.submit(() -> { 
     try { 
      foo(); // some long execution function 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    }); 
} 

service.shutdown(); 

System.out.println("We're done! All threads are finished!"); 

Meine Frage:

  • Warum submit() und shutdown() nicht warten, bis alle Threads und Drucke fertig werden «Wir sind fertig! Alle Gewinde sind fertig! » gleich nach dem Anruf von service.shutdown();?

Antwort

7

Die Antwort ist in dem ExecutorService.shutdown() Javadoc zur Verfügung:

Diese Methode wartet nicht vorher Aufgaben vorgelegt Ausführung abzuschließen. Verwenden Sie awaistTermination, um dies zu tun.

Wenn Sie möchten, für die Threads warten, Arbeit zu beenden Sie haben folgende Möglichkeiten:

  • erhalten Future Instanzen zurück von submit() und rufen get() auf jeder Future Instanz
  • nach shutdown auf service Aufruf Anruf awaitTermination auf service, bis es true
  • anstelle von cal ling submit auf service Ihre Runnable Instanzen zu einem java.util.List hinzufügen und diese Liste der invokeAll Methode auf service
+0

tun Meine Themen ändern sich nicht Geben Sie einen beliebigen Wert zurück, daher scheint die zweite Option relevanter zu sein. –

+0

@MikeB. 'submit' gibt ein' Future' zurück, unabhängig davon, ob Sie ein 'Runnable' oder' Callable' übergeben. In beiden Fällen wartet der Aufruf von 'get()' auf einem 'Future' darauf, dass der Thread seine Arbeit beendet. Bevor Sie 'awaitTermination' aufrufen, müssen Sie' shutdown' aufrufen. –

+0

'awaistTermination()' benötigt ein Zeitlimit, um anzugeben, aber in meinem Fall weiß ich nicht, wie viel Zeit es dauern sollte, also welchen Wert ich als 'Timeout' angeben muss, um sicherzustellen, dass alle Threads beendet sind richtig und nicht gezwungen, wegen "Timeout" zu stoppen? Aus der Dokumentation: * «Blockiert, bis alle Tasks nach einer Shutdown-Anforderung ausgeführt wurden oder das Zeitlimit überschritten wird oder der aktuelle Thread unterbrochen wird **, je nachdem, was zuerst eintritt **.» * –

1

Thanks @, hier Adam Siemion Vorschläge genannt passiert eine endgültige Code lautet:

ExecutorService service = Executors.newFixedThreadPool(cpuCoresNum); 

int itNum = 1; 

for (int i = 0; i < cpuCoresNum; i++) { 

    int treadID = itNum++; 

    service.submit(() -> { 
     Thread.currentThread().setName("Thread_#" + treadID); 
     try { 
      foo(); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    }); 
} 

// wait until all threads will be finished 
service.shutdown(); 
try { 
    service.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS); 
} catch (InterruptedException e) { 
    e.printStackTrace(); 
} 
1

Empfohlene Art und Weise aus Orakeldokumentationsseite von ExecutorService:

void shutdownAndAwaitTermination(ExecutorService pool) { 
    pool.shutdown(); // Disable new tasks from being submitted 
    try { 
    // Wait a while for existing tasks to terminate 
    if (!pool.awaitTermination(60, TimeUnit.SECONDS)) { 
     pool.shutdownNow(); // Cancel currently executing tasks 
     // Wait a while for tasks to respond to being cancelled 
     if (!pool.awaitTermination(60, TimeUnit.SECONDS)) 
      System.err.println("Pool did not terminate"); 
    } 
    } catch (InterruptedException ie) { 
    // (Re-)Cancel if current thread also interrupted 
    pool.shutdownNow(); 
    // Preserve interrupt status 
    Thread.currentThread().interrupt(); 
    } 

shutdown(): Initiiert ein ordnungsgemäßes Herunterfahren, bei dem zuvor übergebene Aufgaben ausgeführt werden, aber keine neuen Aufgaben angenommen werden.

shutdownNow(): Versuche, alle aktiv ausgeführten Tasks zu stoppen, die Verarbeitung wartender Tasks anhalten und eine Liste der Tasks zurückgeben, die auf ihre Ausführung warteten.

In obigen Beispiel, wenn Ihre Aufgaben mehr Zeit nehmen, um abzuschließen, können Sie, wenn die Bedingung zu, während Bedingung

ersetzen

if (!pool.awaitTermination(60, TimeUnit.SECONDS)) 

mit

while(!pool.awaitTermination(60, TimeUnit.SECONDS)) { 
    Thread.sleep(60000); 
}