Java Language
CompletableFuture
Suche…
Einführung
CompletableFuture ist eine in Java SE 8 hinzugefügte Klasse, die die Future-Schnittstelle von Java SE 5 implementiert. Neben der Unterstützung der Future-Schnittstelle werden viele Methoden hinzugefügt, die einen asynchronen Rückruf ermöglichen, wenn die Zukunft abgeschlossen ist.
Konvertieren Sie die Blockierungsmethode in asynchron
Die folgende Methode dauert je nach Verbindung eine oder zwei Sekunden, um eine Webseite abzurufen und die Textlänge zu zählen. Was auch immer der Thread aufruft, wird für diesen Zeitraum blockiert. Außerdem wird eine Ausnahme zurückgegeben, die später nützlich ist.
public static long blockingGetWebPageLength(String urlString) {
try (BufferedReader br = new BufferedReader(new InputStreamReader(new URL(urlString).openConnection().getInputStream()))) {
StringBuilder sb = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
sb.append(line);
}
return sb.toString().length();
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
Dadurch wird es in eine Methode konvertiert, die sofort zurückgegeben wird, indem der Aufruf der blockierenden Methode in einen anderen Thread verschoben wird. Standardmäßig wird die supplyAsync-Methode den Lieferanten im allgemeinen Pool ausführen. Für eine Blockierungsmethode ist dies wahrscheinlich keine gute Wahl, da die Threads in diesem Pool möglicherweise erschöpft sind, weshalb ich den optionalen Parameter service hinzugefügt habe.
static private ExecutorService service = Executors.newCachedThreadPool();
static public CompletableFuture<Long> asyncGetWebPageLength(String url) {
return CompletableFuture.supplyAsync(() -> blockingGetWebPageLength(url), service);
}
Um die Funktion asynchron zu verwenden, sollte eine der Methoden verwendet werden, die das Aufrufen eines Lamdas mit dem Ergebnis des Lieferanten zulässt, wenn es abgeschlossen ist, beispielsweise thenAccept. Es ist auch wichtig, ausnahmsweise oder eine Methode zum Protokollieren der möglicherweise aufgetretenen Ausnahmen zu verwenden.
public static void main(String[] args) {
asyncGetWebPageLength("https://stackoverflow.com/")
.thenAccept(l -> {
System.out.println("Stack Overflow returned " + l);
})
.exceptionally((Throwable throwable) -> {
Logger.getLogger("myclass").log(Level.SEVERE, "", throwable);
return null;
});
}
Einfaches Beispiel für CompletableFuture
In dem folgenden Beispiel calculateShippingPrice
Methode 'dispatchShippingPrice' die Versandkosten, was einige Verarbeitungszeit in Anspruch nimmt. In einem realen Beispiel würde dies zum Beispiel die Kontaktaufnahme mit einem anderen Server sein, der den Preis basierend auf dem Gewicht des Produkts und der Versandart zurückgibt.
Indem Sie dies über CompletableFuture
asynchrone Weise modellieren, können wir verschiedene Arbeiten in der Methode fortsetzen (z. B. Berechnung der Verpackungskosten).
public static void main(String[] args) {
int price = 15; // Let's keep it simple and work with whole number prices here
int weightInGrams = 900;
calculateShippingPrice(weightInGrams) // Here, we get the future
.thenAccept(shippingPrice -> { // And then immediately work on it!
// This fluent style is very useful for keeping it concise
System.out.println("Your total price is: " + (price + shippingPrice));
});
System.out.println("Please stand by. We are calculating your total price.");
}
public static CompletableFuture<Integer> calculateShippingPrice(int weightInGrams) {
return CompletableFuture.supplyAsync(() -> {
// supplyAsync is a factory method that turns a given
// Supplier<U> into a CompletableFuture<U>
// Let's just say each 200 grams is a new dollar on your shipping costs
int shippingCosts = weightInGrams / 200;
try {
Thread.sleep(2000L); // Now let's simulate some waiting time...
} catch(InterruptedException e) { /* We can safely ignore that */ }
return shippingCosts; // And send the costs back!
});
}