Categories

  • articles

Tags

  • java

Just wanted to highlight what thread is used in regards to Java Futures in Java 8. The flow of execution. Basicly the differences between the normal and Async function in futures.

First lets start of real easy. We will be looking at a CompletionStage function thenAccept, but this applies to all CompletionStage Functions. When you call the thenAccept and the future is completed it will execute the Consumer in the Thread doing the thenAccept call. When you do a the Async (thenAcceptAsync) version it will always execute on the ExecutorService (either provided or build in one). Just a quick note it is best practice to always use your own executor service.

When the thenAccept (Non-Async) is called and the Supplier has not completed it will execute in the thread that performed the execution of the Supplier. As stated above the Async (theAcceptAsync) will always request a thread from the ExecutorService to do the Consumption.

Future State Async Non-Async
Completed Thread from Executor Call Thread
Not Completed Thread from Executor Future Thread

Below is just a quick example of how to do the test on your own… I know it is trivial but I like tests.

package com.test;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;

public class Test20Thread {

  public static void main(String[] args) {

    Thread th1 = new Thread(() -> task(), "master thread");
    th1.start();

  }

  public static void task() {
    // Executor Service that names my threads
    ExecutorService exeService = Executors.newFixedThreadPool(6, new ThreadFactory() {

      final AtomicInteger  counter  = new AtomicInteger();

      @Override
      public Thread newThread(Runnable r) {
        return new Thread(r, "PoolThread : " + counter.getAndIncrement());
      }
    });

    // Test 1 : Normal Future Completed
    System.out.println("-- Test 1 : Normal Future Completed");
    CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
      System.out.println("Return Thead Supplier [" + Thread.currentThread().getName() + "]");
      return "Cow";
    }, exeService);

    System.out.println("Is Done 1 " + future.isDone());
    sleep(1000);
    System.out.println("Is Done 2 " + future.isDone());

    future.thenAccept(cow -> {
      System.out.println("theAccept: " + cow + " in [" + Thread.currentThread().getName() + "]");
    });

    // Test 2 : Async Future Completed
    System.out.println();
    System.out.println("-- Test 2 : Async Future Completed");
    future = CompletableFuture.supplyAsync(() -> {
      System.out.println("Return Thead Supplier [" + Thread.currentThread().getName() + "]");
      return "Cow";
    }, exeService);

    System.out.println("Is Done 1 " + future.isDone());
    sleep(1000);
    System.out.println("Is Done 2 " + future.isDone());

    future.thenAcceptAsync(cow -> {
      System.out.println("theAccept: " + cow + " in " + Thread.currentThread().getName());
    }, exeService);

    sleep(2000);

    // Test 3 : Normal Future Not Completed
    System.out.println();
    System.out.println("-- Test 3 : Normal Future Not Completed");
    future = CompletableFuture.supplyAsync(() -> {
      sleep(1000);
      System.out.println("Return Thead Supplier [" + Thread.currentThread().getName() + "]");
      return "Cow";
    }, exeService);

    System.out.println("Is Done 1 " + future.isDone());

    future.thenAccept(cow -> {
      System.out.println("theAccept: " + cow + " in [" + Thread.currentThread().getName() + "]");
    });
    System.out.println("Is Done 2 " + future.isDone());

    sleep(2000);

    // Test 4 : Async Future Not Completed
    System.out.println();
    System.out.println("-- Test 4 : Async Future Not Completed");
    future = CompletableFuture.supplyAsync(() -> {
      sleep(1000);
      System.out.println("Return Thead Supplier [" + Thread.currentThread().getName() + "]");
      return "Cow";
    }, exeService);

    System.out.println("Is Done 1 " + future.isDone());

    future.thenAcceptAsync(cow -> {
      System.out.println("theAccept: " + cow + " in " + Thread.currentThread().getName());
    }, exeService);

    System.out.println("Is Done 2 " + future.isDone());

    sleep(2000);
  }

  private static void sleep(long time) {
    try {
      Thread.sleep(time);
    } catch (InterruptedException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }

}

Below is the output for the execution of above.

-- Test 1 : Normal Future Completed
Is Done 1 false
Return Thead Supplier [PoolThread : 0]
Is Done 2 true
theAccept: Cow in [master thread]

-- Test 2 : Async Future Completed
Is Done 1 false
Return Thead Supplier [PoolThread : 1]
Is Done 2 true
theAccept: Cow in PoolThread : 2

-- Test 3 : Normal Future Not Completed
Is Done 1 false
Is Done 2 false
Return Thead Supplier [PoolThread : 3]
theAccept: Cow in [PoolThread : 3]

-- Test 4 : Async Future Not Completed
Is Done 1 false
Is Done 2 false
Return Thead Supplier [PoolThread : 4]
theAccept: Cow in PoolThread : 5

Part 2 is now avialble!