Java Language
CompletableFuture
Szukaj…
Wprowadzenie
CompletableFuture to klasa dodana do Java SE 8, która implementuje interfejs Future z Java SE 5. Oprócz obsługi interfejsu Future dodaje wiele metod, które pozwalają na asynchroniczne wywołanie zwrotne po zakończeniu przyszłości.
Konwertuj metodę blokowania na asynchroniczną
Poniższa metoda zajmie sekundę lub dwie w zależności od połączenia, aby pobrać stronę internetową i policzyć długość tekstu. Jakikolwiek wątek nazywa, będzie blokować na ten czas. Zwraca także wyjątek, który jest przydatny później.
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);
}
}
Konwertuje to na metodę, która natychmiast powróci, przenosząc wywołanie metody blokującej do innego wątku. Domyślnie metoda supplyAsync uruchomi dostawcę we wspólnej puli. W przypadku metody blokowania prawdopodobnie nie jest to dobry wybór, ponieważ można wyczerpać wątki w tej puli, dlatego dodałem opcjonalny parametr usługi.
static private ExecutorService service = Executors.newCachedThreadPool();
static public CompletableFuture<Long> asyncGetWebPageLength(String url) {
return CompletableFuture.supplyAsync(() -> blockingGetWebPageLength(url), service);
}
Aby użyć funkcji w sposób asynchroniczny, należy użyć jednej z metod, które akceptują lamdę, która ma zostać wywołana z wynikiem dostawcy po jej zakończeniu, np. Wtedy Akceptuj. Ważne jest również, aby używać wyjątku lub obsługiwać metodę w celu rejestrowania wyjątków, które mogły się zdarzyć.
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;
});
}
Prosty przykład CompletableFuture
W poniższym przykładzie calculateShippingPrice
metody oblicza koszt wysyłki, co wymaga pewnego czasu przetwarzania. W prawdziwym przykładzie byłoby to np. Skontaktowanie się z innym serwerem, który zwraca cenę na podstawie wagi produktu i metody wysyłki.
Modelując to w asynchroniczny sposób za pomocą CompletableFuture
, możemy kontynuować różne prace w metodzie (tj. Obliczanie kosztów pakowania).
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!
});
}