2016-12-27 4 views
3

Ich habe ein kleines Beispiel zum Lesen einer Textdatei erstellt und den Anruf mit CompletableFuture umbrechen.mit Lieferanten in CompleableFuture ergibt anderes Ergebnis als mit Lambda

public class Async { 
    public static void main(String[] args) throws Exception { 
     CompletableFuture<String> result = ReadFileUsingLambda(Paths.get("path/to/file")); 
     result.whenComplete((ok, ex) -> { 
      if (ex == null) { 
       System.out.println(ok); 
      } else { 
       ex.printStackTrace(); 
      } 
     }); 
    } 

    public static CompletableFuture<String> ReadFileUsingSupplier(Path file) throws Exception { 
     return CompletableFuture.supplyAsync(new Supplier<String>() { 
      @Override 
      public String get() { 
       try { 
        return new String(Files.readAllBytes(file)); 
       } catch (IOException e) { 
        e.printStackTrace(); 
        return "test"; 
       } 
      } 
     }, ForkJoinPool.commonPool()); 
    } 

    public static CompletableFuture<String> ReadFileUsingLambda(Path file) throws Exception { 
     return CompletableFuture.supplyAsync(() -> { 
      try { 
       return new String(Files.readAllBytes(file)); 
      } catch (IOException e) { 
       e.printStackTrace(); 
       return "test"; 
      } 
     } , ForkJoinPool.commonPool()); 
    } 
} 

Dieser Code gibt nichts zurück. Es wird ausgeführt und "nichts passiert", keine Fehler oder Ausgaben. Wenn ich ReadFileUsingSupplier statt ReadFileUsingLambda rufe, bekomme ich den Dateiinhalt in der Konsole ausgedruckt!

Das macht für mich keinen Sinn, weil ein Lambda eine Abkürzung für das Schreiben einer Inline-Funktion ist und das Verhalten nicht ändern sollte, aber in diesem Beispiel scheint es.

Antwort

4

Ich denke, es ist nur eine Frage der Ausführung Timing - der Lambda kann ein wenig mehr ausführen, so dass das Programm beenden, bevor Sie fertig mit dem Lesen der Datei sind.

Versuchen Sie folgendes:

  • eine Thread.sleep(1000); als erste Anweisung im try-Block in ReadFileUsingSupplier hinzufügen und Sie werden nicht sehen, fügen Sie keine Ausgabe
  • eine Thread.sleep(1000); am Ende Ihres Haupt wenn ReadFileUsingLambda mit und Sie wird die erwartete Ausgabe

Um sicherzustellen, dass Ihre Hauptausgang nicht sehen, bevor die Zukunft abgeschlossen ist, können Sie anrufen:

result.join(); 
+0

danke. Dies hat den Trick gemacht, aber vorwärts gehen, wie kann ich sicherstellen, dass mein Programm nicht beendet wird, bis ich das Ergebnis von CompletableFuture –

+2

@SulAga zurückbekommen Sie können einfach 'result.get()' oder 'result.join()' – assylias

+0

aufrufen Also ist das Join oder Get ein blockierender Aufruf? ist es eine Blockierung für den Haupt-Thread oder CompletableFuture-Thread? ist das ein Problem, d. h. blockiert –

2

Wie bereits erwähnt, müssen Sie in beiden Fällen result.join() ausführen, um zu vermeiden, dass der Hauptthread zu schnell beendet wird.

Es scheint, dass es eine Strafe für die Verwendung von Lambdas vs anonyme Schließungen gibt, während die JVM aufwärmt, danach ist die Leistung gleich. Ich fand diese Information bei another SO thread - die wiederum verbindet a performance study by Oracle.

Als eine Nebenbemerkung ist es keine gute Idee zu Thread.sleep(), seltsame Timing-Probleme zu beheben, immer. Das Herausfinden der Ursache und das Anwenden der geeigneten Maßnahmen würde viel klarer sein, wenn sie von Ihnen oder von anderen erneut gelesen werden, z.

System.out.println(result.get(5, TimeUnit.SECONDS)); 

Dies ermöglicht es Ihnen, auch die .join() zu entfernen.

Verwandte Themen