Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

thenApplyAsync #336

Open
wjiayis opened this issue Nov 29, 2022 · 2 comments
Open

thenApplyAsync #336

wjiayis opened this issue Nov 29, 2022 · 2 comments

Comments

@wjiayis
Copy link

wjiayis commented Nov 29, 2022

Hi there,

I modified a question from a past year paper to understand how thenApplyAsync works.

class Code {
    public static void main(String[] args) {
        CompletableFuture<Integer> ten = CompletableFuture.supplyAsync(() -> 10);
        ten.thenApplyAsync(plus(1))
            .thenApplyAsync(plus(50))
            .thenApplyAsync(plus(20)).join();
    }

    private static Function<Integer,Integer> plus(int i) {
        return x -> {
            doSomething(i);
            System.out.println(x + i);
            return x + i;
        };
    }

    private static void doSomething(int i) {
        try {
            Thread.sleep(i * 100);
        } catch (InterruptedException e) {}
    }
}

Output is

11
61
81

with some latency before the printing of both 61 and 81.

I see why there is a latency before the printing of 61, I don't really understand why there is latency too before the printing of 81.

Would appreciate some help! Thanks in advance:)

@JuliaPoo
Copy link

JuliaPoo commented Nov 29, 2022

When chaining thenApply or thenApplyAsync, the result has to arrive before the callback can be executed. In your case

ten.thenApplyAsync(plus(1)) // `plus(1)` executes only after `ten` has arrived (immediate because it's a completed future)
    .thenApplyAsync(plus(50)) // `plus(50)` executes only after the previous `plus(1)` has been executed
    .thenApplyAsync(plus(20)).join(); // `plus(20)` executes only after the previous `plus(20)` has been executed

Then is because thenApply and thenApplyAsync is used to chain operations. E.g., if you wanna compute f(g(x)), you need to compute g(x) before u can compute f(g(x)). The same thing is happening here.

By the way, a little misnomer is that thenApply and thenApplyAsync are actually equally 'async'. The difference between the two is how java handles the scheduling. E.g, in thenApplyAsync, you're able to specify which thread pool to execute the function.

For our module, it's not really useful? An example use case for the ___Async variants is if you have a server that has two main components, one of which is say a "network component" that handles incoming requests and responds to them. If you want the server to be responsive, you'd never schedule CPU-intensive operations on the thread pool that handles the network component, because then you'll be blocking operations that should be handled first. In this case you don't want to use java's default scheduler, and would use the ___Async variants for that additional control.

@yewey2
Copy link

yewey2 commented Nov 29, 2022

Interesting note about thenApplyAsync vs thenApply!

So to have lesser latency between 61 and 81, should the code be modified as below, keeping the spirit that the final sum is 81?

    public static void main(String[] args) {
        CompletableFuture<Integer> zero = CompletableFuture.supplyAsync(() -> 0);

        CompletableFuture<Integer> ten = CompletableFuture.supplyAsync(() -> 10);
        CompletableFuture<Integer> eleven = ten.thenApplyAsync(plus(1));
        
        CompletableFuture<Integer> sixtyone = eleven.thenApplyAsync(plus(50));
        CompletableFuture<Integer> twenty=zero.thenApplyAsync(plus(20)); // this prints 20 
        sixtyone.thenCombine(twenty, (a, b) -> plus(b).apply(a)).join();
    }

Edit: forgot semicolons
Edit2: realised the code has a side effect of printing 20... any way to circumvent this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants