-1

currently i have a requirement to make async task to sync in completablefuture. Eg. Task A and Task B are completablefuture. Task B runs when Task A is completed. This works fine for single time. Suppose if I make it to run in foor loop, obviously it will create n number of async calls to achieve the outcome. Because of this, i'm getting o/p like below

A
B
A
A
B
B
A
B
A
A
A

I want to achieve like

A
B
A
B
A
B
A
B

Here is the code,

package com.demo.completable.combine;

import javax.xml.stream.Location;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

public class ThenCompose {

    synchronized CompletableFuture<User> getUserDetails(String name) {
        return CompletableFuture.supplyAsync(() -> {
            return UserService.getUser(name);
        });
    }

    synchronized CompletableFuture<Double> getRating(User user) {
        return CompletableFuture.supplyAsync(() -> {
            return CreditRating.getCreditRating(user);
        });
    }

     synchronized CompletableFuture<String> getResult(Double rating) {
        return CompletableFuture.supplyAsync(()-> {
            return "welcome world";
        });
    }

    public void main() throws InterruptedException, ExecutionException {

        ThenCompose cc = new ThenCompose();

        // then apply

        CompletableFuture<CompletableFuture<Double>> result = cc.getUserDetails("kumaran").thenApply(user -> {
            return cc.getRating(user);
        });

        // then compose

        for (int i = 1; i <= 15; i++) {

        CompletableFuture<Double> taskA = cc.getUserDetails("mike").thenCompose(user -> {
                    System.out.println("Task A --- " +Thread.currentThread().getName() + "--" + LocalTime.now());
                    return cc.getRating(user);

        });

        CompletableFuture<String> fileLocation =
                taskA.thenCompose(ts -> {
                        System.out.println("Task B --- " +Thread.currentThread().getName() + "--- " + LocalTime.now());
                        return getResult(ts);



        });
        }

    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
            ThenCompose tc = new ThenCompose();
            tc.main();
    }

}

putting join and get will work but I'm not supposed to use both join and get. kindly suggest a solution.

  • I don't think that you are forced to use get with join. You can try thenAccept() with joins. You can refer https://www.thetechnojournals.com/2019/10/how-to-read-large-file-in-java.html where it uses CompletableFuture with join. Though it uses get() but you can try to replace that with thenAccept(). – Ashok Prajapati Nov 05 '19 at 13:40
  • yes i have used thenAccept() also. it makes no difference. what i want is like say, i'm running the above code in loop for 3 times for hitting an api. and i want to behave like below ` Thread 1 - Request 1, Response 1 Thread 2 - Request 2, Response 2 Thread 3 - Request 3, Response 3 ` but what i'm getting currently is like below ` Thread 1 - Request 1 Thread 2 - Request 2 Thread 3 - Request 3 Thread 1 - Response 1 Thread 2 - Response 2 Thread 3 - Response 3 ` – Learning Path Nov 05 '19 at 14:12

1 Answers1

0

Please try below code which executes the tasks in sequence. It will give you the expected result.

static Integer methA(int seq) {
    System.out.println("A-"+seq);
    return seq;
}
static Integer methB(int seq) {
    System.out.println("B-"+seq);
    return seq;
}
public static void main(String[] args) throws InterruptedException, ExecutionException {
    System.out.println("Main started:");
    CompletableFuture<Integer> ft = null;
    for(int a=0;a<15;a++) {
        final int seq = a;
        if(ft==null) {
            ft = CompletableFuture.supplyAsync(()->methA(seq))
                    .thenApply(s->methB(s));
        }else {
            ft.thenApply((s)->methA(seq))
            .thenApply(s->methB(s));
        }
    }
    ft.thenAccept(s->System.out.println("Thread completed..."+s));
    System.out.println("Main ended:");
}
Ashok Prajapati
  • 374
  • 2
  • 7
  • thanks @Ashok Prajapati but since you have used join, it works. but my use case here is not to use a join. i'm looking for some chain kind of implementation. `for(int i=0;i<15;i++) { chain = chain.thenApply() } chain.complete() - this starts the chain once above loop completed` – Learning Path Nov 06 '19 at 08:59
  • @LearningPath, I have updated my answer and solved the issue without join or get. I did it by creating a chain on same completable future object. Hope it should solve your problem. – Ashok Prajapati Nov 06 '19 at 12:33
  • thanks @Ashok Prajapati. exactly looking for the same. i will try to implement it in my use case. – Learning Path Nov 07 '19 at 05:35