Odpowiednik Java C # async / await?


151

Jestem normalnym programistą C #, ale od czasu do czasu tworzę aplikacje w języku Java. Zastanawiam się, czy istnieje odpowiednik Java C # async / await? W prostych słowach, jaki jest odpowiednik Java:

async Task<int> AccessTheWebAsync()
{ 
    HttpClient client = new HttpClient();
    var urlContents = await client.GetStringAsync("http://msdn.microsoft.com");
    return urlContents.Length;
}

7
Dlaczego miałoby to być miłe: Callback jako oświadczenie naszych pokoleń Miguela de Icaza.
andrewdotn

Obecnym rozwiązaniem Javy nie jest zajmowanie się rzeczywistymi wartościami poprzedzonymi prefiksem async, ale używanie zamiast tego wartości Futurelub Observable.
SD

1
Nie ma odpowiednika. I to boli. Jeszcze jedna brakująca funkcja, do której potrzebujesz skomplikowanych obejść i bibliotek, bez osiągnięcia tego samego efektu, co te dwa proste słowa.
spyro

Warto zauważyć, że przez długi czas projektanci Javy starali się zachować wsteczną kompatybilność kodu bajtowego Javy, wprowadzając jedynie zmiany w bibliotekach i cukry syntetyczne wokół istniejących funkcji. Zwróć uwagę na fakt, że typy generyczne nie przechowują informacji o typach w czasie wykonywania, a metody lambdery są implementowane jako obiekt implementujący interfejs . async / await wymagałoby bardzo dużych zmian w kodzie bajtowym, aby były możliwe, dlatego nie spodziewałbym się, że w najbliższym czasie pojawi się w java.
Philip Couling

Odpowiedzi:


140

Nie, nie ma żadnego odpowiednika async / await w Javie - ani nawet w C # przed v5.

Tworzenie automatu stanowego za kulisami jest dość złożoną funkcją językową.

Obsługa języków asynchronicznych / współbieżnych w Javie jest stosunkowo niewielka , ale java.util.concurrentpakiet zawiera wiele przydatnych klas . (Niezupełnie równoważne z biblioteką zadań równoległych, ale najbliższe jej przybliżenie).


15
@ user960567: Nie, chodzi mi o to, że jest to funkcja językowa - nie można jej umieszczać wyłącznie w bibliotekach. Nie sądzę, aby był zaplanowany jakiś odpowiednik przynajmniej dla Java 8.
Jon Skeet

10
@ user960567: Musisz rozróżnić używaną wersję języka C # od używanej wersji .NET. async / await to funkcja języka - została wprowadzona w C # 5. Tak, możesz użyć Microsoft.Bcl.Async, aby użyć async / await dla platformy .NET 4, ale nadal musisz używać kompilatora C # 5.
Jon Skeet

5
@rozar: Nie, nie bardzo. Istnieje już wiele opcji asynchroniczności - ale RxJava nie zmienia języka w sposób, w jaki zrobił to C #. Nie mam nic przeciwko Rx, ale to nie to samo, co async w C # 5.
Jon Skeet

11
@DtechNet: Cóż, jest wiele maszyn JVM, które są asynchroniczne, tak ... to jednak bardzo różni się od rzeczywistych funkcji języka obsługujących asynchronię. (W .NET było dużo asynchronii przed async / await ... ale async / await znacznie ułatwia to wykorzystanie.)
Jon Skeet

1
@ Aarkon: Powiedziałbym, że jeśli nie ma wyraźnego wsparcia językowego , odpowiedź jest nadal poprawna. To nie tylko kwestia bibliotek, które upraszczają planowanie - ważny jest tutaj cały sposób, w jaki kompilator C # buduje maszynę stanów.
Jon Skeet

41

awaitWykorzystuje kontynuację wykonać dodatkowy kod kiedy asynchroniczne finalizuje pracy ( client.GetStringAsync(...)).

Tak więc, jako najbardziej zbliżone przybliżenie, CompletableFuture<T>użyłbym Task<TResult>rozwiązania opartego na (odpowiedniku Java 8 do .net ) do asynchronicznego przetwarzania żądania HTTP.

ZAKTUALIZOWANO 25-05-2016 do AsyncHttpClient v.2 wydanego 13 kwietnia 2016:

Tak więc odpowiednik Java 8 przykładu OP AccessTheWebAsync()jest następujący:

CompletableFuture<Integer> AccessTheWebAsync()
{
    AsyncHttpClient asyncHttpClient = new DefaultAsyncHttpClient();
    return asyncHttpClient
       .prepareGet("http://msdn.microsoft.com")
       .execute()
       .toCompletableFuture()
       .thenApply(Response::getResponseBody)
       .thenApply(String::length);
}

To użycie pochodzi z odpowiedzi na pytanie Jak uzyskać CompletableFuture z żądania Async Http Client? i co jest zgodne z nowym interfejsem API udostępnionym w wersji 2 AsyncHttpClient wydanym 13 kwietnia 2016 r., który ma już wewnętrzną obsługę CompletableFuture<T>.

Oryginalna odpowiedź przy użyciu wersji 1 AsyncHttpClient:

W tym celu mamy dwa możliwe podejścia:

  • pierwsza wykorzystuje nieblokujące IO i ja to nazywam AccessTheWebAsyncNio. Jednak ponieważ AsyncCompletionHandlerjest to klasa abstrakcyjna (zamiast funkcjonalnego interfejsu), nie możemy przekazać lambdy jako argumentu. Jest to więc nieunikniona gadatliwość ze względu na składnię klas anonimowych. Jednak to rozwiązanie jest najbardziej zbliżone do przepływu wykonywania danego przykładu C # .

  • druga jest nieco mniej szczegółowa, ale prześle nowe zadanie, które ostatecznie zablokuje wątek f.get()do momentu zakończenia odpowiedzi.

Pierwsze podejście , bardziej szczegółowe, ale nie blokujące:

static CompletableFuture<Integer> AccessTheWebAsyncNio(){
    final AsyncHttpClient asyncHttpClient = new AsyncHttpClient();
    final CompletableFuture<Integer> promise = new CompletableFuture<>();
    asyncHttpClient
        .prepareGet("https://msdn.microsoft.com")
        .execute(new AsyncCompletionHandler<Response>(){
            @Override
            public Response onCompleted(Response resp) throws Exception {
                promise.complete(resp.getResponseBody().length());
                return resp;
            }
        });
    return promise;
}

Drugie podejście mniej rozwlekłe, ale blokujące wątek:

static CompletableFuture<Integer> AccessTheWebAsync(){
    try(AsyncHttpClient asyncHttpClient = new AsyncHttpClient()){
        Future<Response> f = asyncHttpClient
            .prepareGet("https://msdn.microsoft.com")
            .execute();
        return CompletableFuture.supplyAsync(
            () -> return f.join().getResponseBody().length());
    }
}

1
Właściwie jest to odpowiednik szczęśliwego przepływu. Nie obejmuje wreszcie obsługi wyjątków i innych. Uwzględnienie ich sprawi, że kod będzie znacznie bardziej złożony i bardziej podatny na błędy.
haimb

1
To nie jest kontynuacja. W tym przykładzie brakuje prawdziwego celu async / await, którym jest zwolnienie bieżącego wątku w celu wykonania innych rzeczy, a następnie kontynuowanie wykonywania tej metody w bieżącym wątku po nadejściu odpowiedzi. (Jest to konieczne, aby wątek interfejsu użytkownika był responsywny lub w celu zmniejszenia zużycia pamięci). W tym przykładzie jest to zwykła synchronizacja wątku blokującego oraz niektóre wywołania zwrotne.
Aleksandr Dubinsky

1
@AleksandrDubinsky Zgadzam się z tobą, gdy wskażesz, że callback może nie działać w wątku dzwoniącego. Masz rację. Nie zgadzam się z blokowaniem wątku. Moja zaktualizowana odpowiedź ZAKTUALIZOWANO w dniu 25-05-2016 nie blokuje.
Miguel Gamboa

1
.... a ten przykład jest dokładnie powodem, dla którego C # jest o wiele prostszy do pisania i czytania podczas wykonywania czynności asynchronicznych. To tylko ból w Javie.
spyro

29

Sprawdź ea-async, który dokonuje przepisywania kodu bajtowego Java, aby całkiem ładnie symulować async / await. Według ich pliku readme: „Jest mocno zainspirowany Async-Await w .NET CLR”


8
Czy ktoś używa tego w produkcji?
Pan Wang z Next Door

1
Wygląda na to, że EA to robi, nie sądzę, żeby wydali pieniądze na coś, co nie nadaje się do produkcji.
BrunoJCM

1
Wydanie pieniędzy na coś, a następnie stwierdzenie, że nie nadaje się do produkcji, jest całkiem normalne; to jedyny sposób na naukę. Można go używać bez ustawień agenta Java w środowisku produkcyjnym; to powinno nieco obniżyć pasek ( github.com/electronicarts/ea-async ).
thoredge

16

async i await to cukry syntaktyczne. Istotą async i await jest maszyna stanowa. Kompilator przekształci kod asynchroniczny / await w maszynę stanu.

Jednocześnie, w celu asynchroniczny / poczekać należy naprawdę wykonalne w rzeczywistych projektach, musimy mieć wiele funkcji asynchroniczny biblioteka we / wy już na miejscu. W przypadku języka C # większość oryginalnych zsynchronizowanych funkcji we / wy ma alternatywną wersję Async. Powodem, dla którego potrzebujemy tych funkcji Async, jest to, że w większości przypadków twój własny kod async / await sprowadza się do pewnej metody Async biblioteki.

Funkcje biblioteki wersji Async w C # są podobne do koncepcji AsynchronousChannel w Javie. Na przykład mamy AsynchronousFileChannel.read, który może zwrócić Future lub wykonać wywołanie zwrotne po zakończeniu operacji odczytu. Ale to nie jest dokładnie to samo. Wszystkie funkcje C # Async zwracają zadania (podobne do Future, ale bardziej wydajne niż Future).

Powiedzmy, że Java obsługuje async / await, a my piszemy taki kod:

public static async Future<Byte> readFirstByteAsync(String filePath) {
    Path path = Paths.get(filePath);
    AsynchronousFileChannel channel = AsynchronousFileChannel.open(path);

    ByteBuffer buffer = ByteBuffer.allocate(100_000);
    await channel.read(buffer, 0, buffer, this);
    return buffer.get(0);
}

Wtedy wyobrażam sobie, że kompilator przekształci oryginalny kod async / await w coś takiego:

public static Future<Byte> readFirstByteAsync(String filePath) {

    CompletableFuture<Byte> result = new CompletableFuture<Byte>();

    AsyncHandler ah = new AsyncHandler(result, filePath);

    ah.completed(null, null);

    return result;
}

A oto implementacja dla AsyncHandler:

class AsyncHandler implements CompletionHandler<Integer, ByteBuffer>
{
    CompletableFuture<Byte> future;
    int state;
    String filePath;

    public AsyncHandler(CompletableFuture<Byte> future, String filePath)
    {
        this.future = future;
        this.state = 0;
        this.filePath = filePath;
    }

    @Override
    public void completed(Integer arg0, ByteBuffer arg1) {
        try {
            if (state == 0) {
                state = 1;
                Path path = Paths.get(filePath);
                AsynchronousFileChannel channel = AsynchronousFileChannel.open(path);

                ByteBuffer buffer = ByteBuffer.allocate(100_000);
                channel.read(buffer, 0, buffer, this);
                return;
            } else {
                Byte ret = arg1.get(0);
                future.complete(ret);
            }

        } catch (Exception e) {
            future.completeExceptionally(e);
        }
    }

    @Override
    public void failed(Throwable arg0, ByteBuffer arg1) {
        future.completeExceptionally(arg0);
    }
}

15
Cukier syntetyczny? Czy masz pomysł, jak zawijać wyjątki wokół kodu asynchronicznego i pętle wokół kodu asynchronicznego?
Akash Kava

39
Zajęcia również są cukrem syntaktycznym. Kompilator tworzy w pełni automatycznie wszystkie drzewa i listy wskaźników funkcji, które normalnie zapisałeś ręcznie. Te funkcje / metody są również cukrem syntaktycznym. Automatycznie generują wszystkie gotówki, które normalnie, będąc prawdziwym programistą, piszą ręcznie. Asembler to także cukier syntaktyczny. Prawdziwi programiści ręcznie piszą kod maszynowy i ręcznie przenoszą go na wszystkie architektury docelowe.
yeoman

32
Myśląc o tym, same komputery są po prostu cukrem syntaktycznym dla l4m3 n00bz. Prawdziwi programiści przylutowują maleńkie układy scalone do drewnianej płytki i łączą je złotym drutem, ponieważ płytki drukowane zawierają cukier syntaktyczny, podobnie jak masowa produkcja, buty czy jedzenie.
yeoman

14

Nie ma odpowiednika C # async / await w Javie na poziomie języka. Koncepcja znana jako włókna, czyli nici współpracujące, czyli lekkie nici, może być interesującą alternatywą. Możesz znaleźć biblioteki Java obsługujące włókna.

Biblioteki Java implementujące Fibers

Możesz przeczytać ten artykuł (z Quasar), aby uzyskać miłe wprowadzenie do włókien. Opisuje, czym są wątki, jak można zaimplementować włókna w JVM i zawiera kod specyficzny dla Quasara.


10
async / await w C # nie jest Fiber. To po prostu magia kompilatora, która używa kontynuacji w Promise ( Taskklasie) przez zarejestrowanie wywołania zwrotnego.
UltimaWeapon

1
@UltimaWeapon Więc co uważacie za włókna?
Aleksandr Dubinsky,

@AleksandrDubinsky Jednym z przykładów jest goroutine.
UltimaWeapon

1
@UltimaWeapon Szukałem wyjaśnienia.
Aleksandr Dubinsky

@AleksandrDubinsky Jestem leniwy, żeby to wyjaśnić. Jeśli naprawdę chcesz wiedzieć, możesz przeszukać artykuł o goroutine.
UltimaWeapon

8

Jak wspomniano, nie ma bezpośredniego odpowiednika, ale bardzo bliskie przybliżenie można stworzyć za pomocą modyfikacji kodu bajtowego Javy (zarówno dla instrukcji async / await, jak i implementacji kontynuacji).

Pracuję teraz nad projektem, który implementuje async / await na górze biblioteki kontynuacji JavaFlow , sprawdź https://github.com/vsilaev/java-async-await

Nie utworzono jeszcze mojo Maven, ale możesz uruchamiać przykłady z dostarczonym agentem Java. Oto jak wygląda kod async / await:

public class AsyncAwaitNioFileChannelDemo {

public static void main(final String[] argv) throws Exception {

    ...
    final AsyncAwaitNioFileChannelDemo demo = new AsyncAwaitNioFileChannelDemo();
    final CompletionStage<String> result = demo.processFile("./.project");
    System.out.println("Returned to caller " + LocalTime.now());
    ...
}


public @async CompletionStage<String> processFile(final String fileName) throws IOException {
    final Path path = Paths.get(new File(fileName).toURI());
    try (
            final AsyncFileChannel file = new AsyncFileChannel(
                path, Collections.singleton(StandardOpenOption.READ), null
            );              
            final FileLock lock = await(file.lockAll(true))
        ) {

        System.out.println("In process, shared lock: " + lock);
        final ByteBuffer buffer = ByteBuffer.allocateDirect((int)file.size());

        await( file.read(buffer, 0L) );
        System.out.println("In process, bytes read: " + buffer);
        buffer.rewind();

        final String result = processBytes(buffer);

        return asyncResult(result);

    } catch (final IOException ex) {
        ex.printStackTrace(System.out);
        throw ex;
    }
}

@async to adnotacja oznaczająca metodę jako wykonywalną asynchronicznie, await () to funkcja, która czeka na CompletableFuture przy użyciu kontynuacji, a wywołanie „return asyncResult (someValue)” jest tym, co finalizuje skojarzoną CompletableFuture / Continuation

Podobnie jak w C #, przepływ sterowania jest zachowywany, a obsługa wyjątków może odbywać się w zwykły sposób (try / catch jak w sekwencyjnie wykonywanych kodzie)


6

Sama Java nie ma równoważnych funkcji, ale istnieją biblioteki innych firm, które oferują podobną funkcjonalność, np . Kilim .


3
Nie sądzę, aby ta biblioteka miała coś wspólnego z tym, co robi async / await.
Natan

5

Najpierw zrozum, czym jest async / await. Jest to sposób na uruchamianie wielu „włókien”, „współprogramów” lub „lekkich wątków” w pojedynczym wątku przez jednowątkową aplikację GUI lub wydajny serwer.

Jeśli nie przeszkadza ci używanie zwykłych wątków, odpowiednikiem Java jest ExecutorService.submit i Future.get. Spowoduje to zablokowanie do zakończenia zadania i zwrócenie wyniku. W międzyczasie inne wątki mogą działać.

Jeśli chcesz skorzystać z czegoś takiego jak włókna, potrzebujesz wsparcia w kontenerze (mam na myśli pętlę zdarzeń GUI lub w module obsługi żądań HTTP serwera) lub pisząc własne.

Na przykład Servlet 3.0 oferuje przetwarzanie asynchroniczne. Oferty JavaFX javafx.concurrent.Task. Nie mają one jednak elegancji cech językowych. Działają poprzez zwykłe wywołania zwrotne.


2
Oto cytat z artykułu, który ponownie uruchamia pierwszy akapit tej odpowiedzi // start quote W przypadku aplikacji klienckich, takich jak Windows Store, Windows Desktop i Windows Phone, podstawową zaletą asynchronizacji jest responsywność. Tego typu aplikacje używają asynchroniczności głównie do utrzymywania responsywności interfejsu użytkownika. W przypadku aplikacji serwerowych podstawową zaletą asynchronii jest skalowalność. msdn.microsoft.com/en-us/magazine/dn802603.aspx
granadaCoder

3

Nie ma nic natywnego dla java, co pozwala to zrobić, jak słowa kluczowe async / await, ale co możesz zrobić, jeśli naprawdę chcesz, to użyć CountDownLatch . Państwo mogli następnie Naśladujcie asynchroniczny / Oczekujcie przekazując tę dookoła (przynajmniej w Java7). Jest to powszechna praktyka w testowaniu jednostkowym systemu Android, w której musimy wykonać wywołanie asynchroniczne (zwykle jest to uruchomione przez moduł obsługi), a następnie poczekać na wynik (odliczać w dół).

Jednak używanie tego w aplikacji w przeciwieństwie do testu NIE jest tym, co polecam. Byłoby to wyjątkowo tandetne, ponieważ CountDownLatch polega na tym, że skutecznie odliczasz odpowiednią liczbę razy i we właściwych miejscach.


3

Stworzyłem i wydałem bibliotekę Java async / await. https://github.com/stofu1234/kamaitachi

Ta biblioteka nie wymaga rozszerzenia kompilatora i realizuje bezstapowe przetwarzanie we / wy w Javie.

    async Task<int> AccessTheWebAsync(){ 
        HttpClient client= new HttpClient();
        var urlContents= await client.GetStringAsync("http://msdn.microsoft.com");
       return urlContents.Length;
    }

   ↓

    //LikeWebApplicationTester.java
    BlockingQueue<Integer> AccessTheWebAsync() {
       HttpClient client = new HttpClient();
       return awaiter.await(
            () -> client.GetStringAsync("http://msdn.microsoft.com"),
            urlContents -> {
                return urlContents.length();
            });
    }
    public void doget(){
        BlockingQueue<Integer> lengthQueue=AccessTheWebAsync();
        awaiter.awaitVoid(()->lengthQueue.take(),
            length->{
                System.out.println("Length:"+length);
            }
            );
    }

1

Java niestety nie ma odpowiednika async / await. Najbliżej można uzyskać prawdopodobnie dzięki ListenableFuture z Guava i łańcuchowi słuchaczy, ale nadal byłoby bardzo kłopotliwe pisanie w przypadkach obejmujących wiele wywołań asynchronicznych, ponieważ poziom zagnieżdżenia bardzo szybko by się zwiększył.

Jeśli nie przeszkadza ci używanie innego języka na JVM, na szczęście w Scali jest async / await, który jest bezpośrednim odpowiednikiem C # async / await z prawie identyczną składnią i semantyką: https://github.com/scala/ async /

Zauważ, że chociaż ta funkcjonalność wymagała dość zaawansowanej obsługi kompilatora w C #, w Scali można ją dodać jako bibliotekę dzięki bardzo potężnemu systemowi makr w Scali, a zatem można ją dodać nawet do starszych wersji Scali, takich jak 2.10. Dodatkowo Scala jest kompatybilna z klasami z Javą, więc możesz napisać kod asynchroniczny w Scali, a następnie wywołać go z Java.

Istnieje również inny podobny projekt o nazwie Akka Dataflow http://doc.akka.io/docs/akka/2.3-M1/scala/dataflow.html, który używa innego sformułowania, ale koncepcyjnie jest bardzo podobny, jednak zaimplementowany za pomocą ograniczonych kontynuacji, a nie makr (więc działa z nawet starszymi wersjami Scali, takimi jak 2.9).


1

Java nie ma bezpośredniego odpowiednika funkcji języka C # o nazwie async / await, jednak istnieje inne podejście do problemu, który async / await próbuje rozwiązać. Nazywa się Project Loom , który zapewni wirtualne wątki dla współbieżności o wysokiej przepustowości. Będzie dostępny w przyszłej wersji OpenJDK.

Takie podejście rozwiązuje również „ problem z kolorowymi funkcjami ”, który ma async / await.

Podobną cechę można znaleźć również w Golangu ( gorutynach ).


0

Jeśli szukasz czystego kodu, który symuluje ten sam efekt co async / await w java i nie masz nic przeciwko blokowaniu wątku, w którym jest wywoływany, dopóki nie zostanie ukończony, na przykład w teście, możesz użyć czegoś takiego jak ten kod:

interface Async {
    void run(Runnable handler);
}

static void await(Async async) throws InterruptedException {

    final CountDownLatch countDownLatch = new CountDownLatch(1);
    async.run(new Runnable() {

        @Override
        public void run() {
            countDownLatch.countDown();
        }
    });
    countDownLatch.await(YOUR_TIMEOUT_VALUE_IN_SECONDS, TimeUnit.SECONDS);
}

    await(new Async() {
        @Override
        public void run(final Runnable handler) {
            yourAsyncMethod(new CompletionHandler() {

                @Override
                public void completion() {
                    handler.run();
                }
            });
        }
    });

0

Biblioteka AsynHelper Java zawiera zestaw klas / metod narzędzi dla takich wywołań asynchronicznych (i oczekiwania).

Jeśli chcesz uruchomić zestaw wywołań metod lub bloków kodu asynchronicznie, to zawiera użyteczną metodę pomocniczą AsyncTask .submitTasks, jak w poniższym fragmencie.

AsyncTask.submitTasks(
    () -> getMethodParam1(arg1, arg2),
    () -> getMethodParam2(arg2, arg3)
    () -> getMethodParam3(arg3, arg4),
    () -> {
             //Some other code to run asynchronously
          }
    );

Jeśli chcesz poczekać, aż wszystkie kody asynchroniczne zostaną uruchomione, można użyć wariantu AsyncTask.submitTasksAndWait.

Ponadto jeśli pożądane jest uzyskanie wartości zwracanej z każdego wywołania metody asynchronicznej lub bloku kodu, można użyć AsyncSupplier .submitSuppliers, aby wynik mógł być następnie uzyskany z tablicy wyników dostawców zwróconych przez metodę. Poniżej znajduje się przykładowy fragment:

Supplier<Object>[] resultSuppliers = 
   AsyncSupplier.submitSuppliers(
     () -> getMethodParam1(arg1, arg2),
     () -> getMethodParam2(arg3, arg4),
     () -> getMethodParam3(arg5, arg6)
   );

Object a = resultSuppliers[0].get();
Object b = resultSuppliers[1].get();
Object c = resultSuppliers[2].get();

myBigMethod(a,b,c);

Jeśli zwracane typy każdej metody różnią się, użyj poniższego rodzaju fragmentu.

Supplier<String> aResultSupplier = AsyncSupplier.submitSupplier(() -> getMethodParam1(arg1, arg2));
Supplier<Integer> bResultSupplier = AsyncSupplier.submitSupplier(() -> getMethodParam2(arg3, arg4));
Supplier<Object> cResultSupplier = AsyncSupplier.submitSupplier(() -> getMethodParam3(arg5, arg6));

myBigMethod(aResultSupplier.get(), bResultSupplier.get(), cResultSupplier.get());

Wynik asynchronicznych wywołań metod / bloków kodu można również uzyskać w innym punkcie kodu w tym samym wątku lub w innym wątku, jak w poniższym fragmencie.

AsyncSupplier.submitSupplierForSingleAccess(() -> getMethodParam1(arg1, arg2), "a");
AsyncSupplier.submitSupplierForSingleAccess(() -> getMethodParam2(arg3, arg4), "b");
AsyncSupplier.submitSupplierForSingleAccess(() -> getMethodParam3(arg5, arg6), "c");


//Following can be in the same thread or a different thread
Optional<String> aResult = AsyncSupplier.waitAndGetFromSupplier(String.class, "a");
Optional<Integer> bResult = AsyncSupplier.waitAndGetFromSupplier(Integer.class, "b");
Optional<Object> cResult = AsyncSupplier.waitAndGetFromSupplier(Object.class, "c");

 myBigMethod(aResult.get(),bResult.get(),cResult.get());
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.