Asynchronous

Java logo 

Agenda

  • Asynchronous programming in Java 5
  • Spring's @Async annotation
  • Hands-on
  • Asynchronous programming in Java 8
  • Hands-on
  • Spring's support for the Servlet 3.0 asynchronous processing
  • Hands-on

π and the Monte Carlo method

PI and Monce Carlo

Given that the ratio of their areas is π / 4 , the value of π can be approximated using a Monte Carlo method.

Java logo 5

Runnable vs. Callable

  • The Runnable is a functional interface and has a single run() method which doesn't accept any parameters and does not return any values:
    
    public interface Runnable {
      public void run();
    }
                  
  • The Callable is a generic interface containing a single call() method – which returns a value V:
    
    public interface Callable<V> {
      V call() throws Exception;
    }
                  

Future

A Future represents the result of an asynchronous computation:


public interface Future<V> {
  boolean cancel(boolean mayInterruptIfRunning);
  boolean isCancelled();
  boolean isDone();
  V get() throws InterruptedException, ExecutionException;
  V get(long timeout, TimeUnit unit)
      throws InterruptedException, ExecutionException,
             TimeoutException;
}
              

Example


 interface PiService {
    Pi compute(int timeToComputeInSeconds)
 }

 class App {
   ExecutorService exec = ...
   PiService ps = ...

   void show(int timeInSeconds) throws Exception {
     Future<Pi> pi = exec.submit(() -> ps.compute(timeInSeconds));
     displayOtherThings(); // do other things while computing π
     displayPi(pi.get());
   }
 }
					

FutureTask

The FutureTask class is an implementation of Future and Runnable, and so may be executed by an Executor.


 FutureTask<Pi> pi =
   new FutureTask<String>(new Callable<Pi>() {
     public Pi call() {
       return ps.compute(timeInSeconds);
   }});
 e.execute(pi);
					

With lambda


 FutureTask<Pi> pi =
   new FutureTask<String>(() -> ps.compute(timeInSeconds));
 e.execute(pi);
					
Spring logo

 @Async


@Service
public class PiService {
  @Async
  public Future<Pi> compute(int timeInSeconds) {
    Pi pi = ...
    return new AsyncResult<Pi>(pi);
  }
}
            

@Configuration
@EnableAsync
public class TaskExecutorConfig {
  @Bean public Executor taskExecutor() {
    ThreadPoolTaskExecutor exe = new ThreadPoolTaskExecutor();
    exe.setCorePoolSize(0);
    exe.setQueueCapacity(0);
    exe.setKeepAliveSeconds(10);
    exe.setThreadNamePrefix("async-");
    exe.setAllowCoreThreadTimeOut(true);
    exe.initialize();
    return exe;
  }
}

Hands-on

Repository on github https://github.com/devonfw-java-advanced/concurrent contains branches:

Hands-on

Future and FutureTask

  • Compute π asynchronously using ExecutorService
  • Compute π asynchronously using Executor
  • Compute π asynchronously using @Async
  • Experiment with Future, e.g. cancel
  • Experiment with ExecutorService, e.g. shutdownNow

The basis of the exercise, branch step-0

Sample solution, branch: step-1

Java logo 8

CompletableFuture

  • The Future does not have any methods to combine the computations or handle possible errors.
  • The CompletableFuture implements the Future and the CompletionStage. The last interface defines the contract for an asynchronous computation step that we can combine with other steps.
  • CompletableFuture has about 50 different methods for composing, combining, and executing asynchronous computation steps and handling errors.

Example 1/2


 interface PiService {
    Pi compute(int timeToComputeInSeconds)
  }

 class App {
   PiService ps = ...
   void show(int timeInSeconds) throws Exception {
     CompletableFuture<Pi> pi = CompletableFuture
       .supplyAsync(() -> ps.compute(timeInSeconds));
     displayOtherThings(); // do other things while computing π
     displayText(pi.get());
   }
 }
					

Example 2/2


        CompletableFuture<?> cs = CompletableFuture
                .supplyAsync(
                    () -> piService.computePi(timeToComputePi1))
                .thenApplyAsync(
                    pi -> pi.getComputedPi() * pi.getComputedPi())
                .thenAcceptAsync(
                    result -> logger.info("result: {}", result));

        displayOtherThings(); // do other things while computing and printing π*π

        cs.join();
					

Hands-on

Repository on github https://github.com/devonfw-java-advanced/concurrent contains branches:

Hands-on

CompletableFuture

Use CompletableFuture to calculate the area of the circle with radius r

  • Without @Async
  • With @Async

The basis of the exercise, branch step-0

Sample solution, branch: step-2

JSR 315: Java Servlet 3.0 Specification
Spring logo
Support for asynchronous processing

@Configuration
public class MvcConfig {
  @Bean public Executor mvcExecutor() {
    return Executors.newCachedThreadPool();
  }
  @Bean public WebMvcConfigurer webMvcConfigurer() {
    return new WebMvcConfigurer() {
      @Override public void configureAsyncSupport(
          final AsyncSupportConfigurer configurer) {
          configurer.setTaskExecutor(
              new ConcurrentTaskExecutor(mvcExecutor()));
      }};
  }
}
            

@RestController
public class PiRest {
    @Autowired
    private PiMultiService ps;

    @GetMapping("rest/pi")
    public Callable<List<Pi>> pi(
            @RequestParam(name = "timeInSeconds"), int timeInSeconds) {
        return () -> {
            return ps.computeMultiPis(timeInSeconds);
        };
    }
}
            

@RestController
public class PiRest {
    @Autowired
    private PiMultiService ps;

    @GetMapping("rest/pi")
    public DeferredResult<List<Pi>> pi(
            @RequestParam(name = "timeInSeconds"),  int timeInSeconds) {
        DeferredResult<List<Pi>> result = new DeferredResult<>();
        result.setResult(piService.computeMultiPis(
            timeToComputeInSeconds, numberOfProbes));
        return result;
    }
}
            

Hands-on

Repository on github https://github.com/devonfw-java-advanced/asynchronous contains branches:

  • step-0 - base version
  • step-1 - asynchronicity in Servlet
  • step-2 - asynchronicity in Service

Hands-on

Asynchronicity in Servlet

  • Prepare asynchronous version of /rest/pi-async on Servlet level.
  • Configure asynchronicity support in WebMvcConfigurer

The basis of the exercise, branch step-0

Sample solution, branch: step-1

Hands-on

Asynchronicity in Service

  • Enable asynchronicity
  • Add asynchronicity the the service using:
    • @Async
    • ExecutorService
    • Executor
  • Experiment with additional Executor beans

The basis of the exercise, branch step-1

Sample solution, branch: step-2