2017-12-14 34 views
-3

Ich rufe eine Methode, die eine Future, einmal für jedes Element in einer List<Principal> zurückgibt, so dass ich mit einer List<Future<UserRecord>> enden.Warte auf jede Zukunft in einer Liste <Future> getan werden

Die Methode, die Future zurückgibt, ist Bibliothekscode und ich habe keine Kontrolle darüber, wie dieser Code ausgeführt wird, alles, was ich habe, ist die Future.

Ich möchte warten, bis alle Future s (Erfolg oder Misserfolg) abgeschlossen sind, bevor Sie fortfahren.

Gibt es eine bessere Art und Weise so, als dies zu tun:

List<Principal> users = new ArrayList<>(); 
// Fill users 
List<Future<UserRecord>> futures = getAllTheFutures(users); 
List<UserRecord> results = new ArrayList<>(futures.size()); 
boolean[] taskCompleted = new boolean[futures.size()]; 
for (int j = 0; j < taskCompleted.length; j++) { 
    taskCompleted[j] = false; 
} 
do { 
    for (int i = 0; i < futures.size(); i++) { 
     if (!taskCompleted[i]) { 
      try { 
       results.add(i, futures.get(i).get(20, TimeUnit.MILLISECONDS)); 
       taskCompleted[i] = true; 
      } catch (TimeoutException e) { 
       // Do nothing 
      } catch (InterruptedException | ExecutionException e) { 
       // Handle appropriately, then... 
       taskCompleted[i] = true; 
      } 
     } 
    } 
} while (allNotCompleted(taskCompleted)); 

Für die Neugierigen:

private boolean allNotCompleted(boolean[] completed) { 
    for (boolean b : completed) { 
     if (!b) 
      return true; 
    } 
    return false; 
} 

Anders als in dieser Antwort auf Waiting on a list of Future ich nicht die Kontrolle über den Code haben, schafft die Future s.

+1

Prüft 'allNotCompleted (taskCompleted)' Schnipsel das gesamte Array und gibt ein Gesamtergebnis zurück? –

+0

Ja, natürlich. – markvgti

+0

Warum verwenden Sie ein Timeout für 'get()'? Welchen Zweck erfüllt es, da Sie immer wieder darauf zurückkommen werden. Was bedeutet "angemessen behandeln" in Ihrem Kontext, da es sich sehr darauf auswirkt, was der Code tun muss und kann. Du bist neu in Java, oder? Sie initialisieren Ihren 'boolean []' auf false, obwohl dies der Standardwert ist. – Kayaman

Antwort

3

Ihr Code kann vereinfacht werden viel. Eine äquivalente Version könnte wie folgt geschrieben werden, es sei denn, Sie haben Anforderungen, die Sie in der Frage nicht angegeben haben.

List<Principal> users = // fill users 
List<Future<UserRecord>> futures = getAllTheFutures(users); 
List<UserRecord> results = new ArrayList<>(); 

for (int i = 0; i < futures.size(); i++) { 
     try { 
      results.add(futures.get(i)); 
     } catch (InterruptedException | ExecutionException e) { 
      // Handle appropriately, results.add(null) or just leave it out 
     } 
    } 
} 
+0

Also das einzige, was Sie entfernt haben, ist die Wartezeit in der get. Macht Sinn. Eine Sache, die Sie verpasst haben, ist, dass das Ergebnis der 'i'ten Zukunft am' i'th Index in 'results' hinzugefügt wird. Alle abfälligen Bemerkungen waren unnötig. Aber vielleicht bekommst du so einfach deine Süssigkeiten. – markvgti

+0

@markvgti Ich sehe nicht wirklich, warum dir der Index wichtig ist. Vielleicht möchten Sie eine separate "List failed" behalten, wo Sie die Principals für die Futures hinzufügen, die eine Ausnahme mit 'failed.add (users.get (i))' geworfen haben. Ich versuche, gute Antworten zu geben, und es ist schwer, das zu tun, wenn es Leute gibt, die schlechte Antworten geben (und Leute, die diese schlechten Antworten aufwerten, weil sie nicht verstehen, dass sie schlecht sind). – Kayaman

+0

Die Dinge werden in der Reihenfolge erzeugt und es ist einfacher, alles in der richtigen Reihenfolge zu halten. Ich schätze Ihren einfachen Code und Ihr Hinweis darauf, dass das Warten unnötig war. Ich kann das Gute und das Schlechte verstehen, sobald ich den Code sehe. Wenn ich von meiner Lösung überzeugt wäre, hätte ich hier nicht um Hilfe gebeten. – markvgti

-1

Angenommen, Ihr Zweck ist es, eine Funktion zu entwickeln, führen Sie alle Futures aus, bis alles erfolgreich abgeschlossen ist. Da Sie Java 8 verwenden, habe ich hier einige Java 8-Syntaxen verwendet.

Ich verwendete java.util.concurrent.CopyOnWriteArrayList, um gleichzeitige Probleme zu vermeiden. Aber es sieht dort nicht notwendig aus. Sie können auch mit den üblichen java.util.List testen. Ich habe den Code allerdings nicht getestet.

+1

Ich dachte, der Code in der Frage wäre schlecht, aber Sie haben es mit einer noch schlechteren Version beantwortet. Bonus (minus) Punkte für die Verwendung von Rekursion, wo es völlig unnötig und höchstwahrscheinlich schädlich ist, da jede Verzögerung im zukünftigen Ausführungsprozess einen Stapelüberlauf riskiert. Sie erstellen auch eine 'CopyOnWriteArrayList' auf jedem Stackframe, und um das Ganze abzurunden, geben Sie niemals die Ergebnisse zurück, die diesen Code nicht nur schlecht, sondern auch kaputt machen. – Kayaman

+1

@Kayaman Aber es ist parallelisiert! – shmosel

+0

Um 800 Millionen Datensätze habe ich 'java.lang.OutOfMemoryError' trotz der Last, die durch' Future :: get' dauert und Ja, ich weiß, dass dieser Fehler von der verwendeten Heap-Größe abhängt. Reale Ausführung möglicherweise auch das gleiche mit einer ähnlichen Anzahl von Datensätzen oder weniger. –

0

Sie könnten einfach eine reduktive Liste machen; Entfernen erfolgreicher Antworten aus Ihrer Liste und Iterieren bis leer.

List<Principal> users = // fill users 
List<Future<UserRecord>> futures = getAllTheFutures(users); 
List<UserRecord> results = new ArrayList<>(); 

for (int i = 0; i < futures.size(); i++) { 
     try { 
      results.add(futures.get(i).get(<how long you want before your application throws exception>)); 

     } 
     catch (InterruptedException | ExecutionException e) { 
      // Handle appropriately, results.add(null) or just leave it out 
     } 
     catch (TimeoutException timeoutEx) { 
      // If the Future retrieval timed out you can handle here 
     } 

    } 
} 

Da Ihre Absicht ist, ein „Set“ von Jobs zu sammeln, bevor voran, zu warten, bis Sie eine Rückkehr auf Thread-Index X in diesem Fall bekommen den letzten zurück Thread eine Zeitkosten (in etwa) geben.

Oder, wenn Sie alle Themen in der Menge zum Abbruch planen wer nicht, können Sie Java 8 CompletableFuture

CompletableFuture[] cfs = futures.toArray(new CompletableFuture[futures.size()]); 

    return CompletableFuture.allOf(cfs) 
      .thenApply(() -> futures.stream() 
            .map(CompletableFuture::join) 
            .collect(Collectors.toList()) 
      ); 
  • Kredit Kayaman für vereinfachte Codebasis verwenden.
+0

Nein, die Absicht war, alles zu sammeln. Es wurde nur auf eine seltsame und verwirrende Weise in der Frage umgesetzt. – Kayaman

+0

Dein Code ist äquivalent zu meinem, außer deins tut nicht was der Titel fragt, zB "Warte auf ** alle ** Zukunft *. Komm Leute, es ist nicht so schwer. – Kayaman

+0

Also wir sind uns einig diese Frage dient grundsätzlich kein Zweck, mit zu beginnen, da die Dokumentation der Zukunft erklärt, wie, und Funktionen zu diesem Zweck implementiert hat .. Sollte schließen Frage vielleicht als rechthaberisch (abgesehen von offensichtlichen Vereinfachung des Beispiels Beispielcode)? – Elysiumplain

Verwandte Themen