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!
    });
}


Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow