Explorer
Explorer

Reputation: 11

Asynchronous CompletableFuture returning synchronously to single thread ExecutorService

I am creating a single thread ExecutorService and assign tasks (CompletableFuture), required to be executed Asynchronously (tried both runAsync and supplyAsync), to that single thread service.

package Executor;

import java.util.Date;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ExecutorResolver {

    ExecutorService es = Executors.newSingleThreadExecutor();
    volatile int counter = 2;
    static int ten = 10;
    static int five = 5;

    public void printer() {

        System.out.println("This thread is complete :" + Thread.currentThread().getName());
        System.out.println(new Date(System.currentTimeMillis()));

    }

    public void execute() {

        CompletableFuture<Void> ct = CompletableFuture.allOf(CompletableFuture.runAsync(() -> {
            try {
                Thread t = new Thread();
                Thread.sleep(ten * 1000);

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, es).thenRunAsync(this::printer), CompletableFuture.runAsync(() -> {
            try {
                Thread t = new Thread();
                Thread.sleep(five * 1000);

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, es).thenRunAsync(this::printer)

        );

    }

    public static void main(String args[]) {

        ExecutorResolver er = new ExecutorResolver();

        er.execute();

        for (int i = 0; i < 1000; i++) {
            System.out.println("Current thread name : " + Thread.currentThread().getName() + i);
        }
        System.out.println(new Date(System.currentTimeMillis()));

    }

}

But they are getting executed synchronously ,

See the console log which waits for thread that sleeps for 10 secs and then the executes the one which sleeps for 5 seconds

Please let me know if this is possible or am i doing something wrong?

Upvotes: 1

Views: 1532

Answers (1)

Tesseract
Tesseract

Reputation: 8139

I believe what you are trying to do is use a single threaded asynchronous programming style. That style is heavily used in Javascript especially node.js applications because it is really well suited for serverside code that has to handle many clients at once which is very well explained in this talk by the creator of node.js. In the Java world however, that programming style is not very widespread for some reason. So maybe you want to learn node.js programming first. Afterwards you can translate the things you learned there to Java. Anyway, I changed your code and I think it is now doing what you intended. The problem is that you can't perform a delay by blocking your thread. Instead you have to use a Future for that as well.

package executor;

import java.util.Date;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.Timer;
import java.util.TimerTask;

public class ExecutorResolver {
    private final ExecutorService es = Executors.newSingleThreadExecutor();
    private static final Timer timer = new Timer();

    public static CompletableFuture<Void> delay(long delay) {
      CompletableFuture<Void> fut = new CompletableFuture<>();
      timer.schedule(new TimerTask() {
        @Override
        public void run() {
          fut.complete(null);
        }
      }, delay);
      return fut;
    }

    public static Date date() {
      return new Date(System.currentTimeMillis());
    }

    public void execute() {
        CompletableFuture<Void> ct = CompletableFuture.allOf(
            CompletableFuture
                .runAsync(() -> {
                    System.out.println(date() + ": started first async operation in thread " + Thread.currentThread());
                }, es)
                .thenComposeAsync(x -> delay(10000), es)
                .thenRunAsync(() -> {
                  System.out.println(date() + ": completed first async operation in thread " + Thread.currentThread());
                }, es)
            ,

            CompletableFuture
                .runAsync(() -> {
                    System.out.println(date() + ": started second async operation in thread " + Thread.currentThread());
                }, es)
                .thenComposeAsync(x -> delay(5000), es)
                .thenRunAsync(() -> {
                  System.out.println(date() + ": completed second async operation in thread " + Thread.currentThread());
                }, es)
          );
    }

    public static void main(String args[]) {
        ExecutorResolver er = new ExecutorResolver();
        er.execute();
    }
}

Upvotes: 1

Related Questions