Introduction
In this tutorial we will learn how to add asynchronous execution of tasks in different threads. Asynchronous execution of methods will be useful to scale services. We can use @EnableAsync and @Async annotations to add asynchronous execution in spring based applications.Realtime time case studies of asynchronous tasks, in a real time for example while attaching more than one attachment into gmail compose action, all attachments are started to upload to gmail server parallel.
And as another example, at system resources usage level to use server resources effectively we can execute bunch of tasks by dividing into small tasks and multiple threads can be executed concurrently. But if threads are completely locked server resources then application execution will be blocked which leads to restarting of server and application. So we are going to use threadpool system to allocate or create a specific number of threads.
At user view asynchronous is to perform multiple tasks at a same is good enough , but at application server manager view asynchronous is the matter of proper utilisation of cpu time and idle resources of server effectively. To avoid block of the application ( which will happen generally if all resources are using by threads or if task queue size is too much more ) we are using ThreadPoolTaskExecutor which is similar to ExecutorService in java.
Steps to implement asynchronous tasks execution
We are going to use @EnableAsync and @Async annotations to enable asynchronous tasks execution- As a vert first step annotate a configuration class with @EnableAsync, so that spring container will try to find a public methods which annotated with @Async 
- As a second step create threadpool by customizing ThreadPoolTaskExecutor by setting up number of threads to be created in threadpool and queue size etc...
- As a third step create a public methods which annotated with @Async annotation, where return type can be CompletableFuture<T>
- Invoke CompletableFuture.allOf(method1, method2...).join(); whereever we want to execute tasks in asynchronous manner
Step1: Enable configuration class with @EnableAsync
@Configuration
@EnableAsync
public class AsynConfig {
// body here
}
Step2: Creating Executor bean by Customising ThreadPoolTaskExecutor
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
@Configuration
@EnableAsync
public class AsynConfig {
// body here
 @Bean("asynExecutor")
 public TaskExecutor geTaskExecutor() {
  ThreadPoolTaskExecutor tpte = new ThreadPoolTaskExecutor();
  tpte.setCorePoolSize(4);
  tpte.setMaxPoolSize(8);
  tpte.setQueueCapacity(200);
  tpte.setThreadNamePrefix("MyAsysnTask:-");
  tpte.initialize();
  return tpte;
 }
}
Step3: creating @Async method
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import com.jai43.jsite.models.Tasks;
@Service
public class TasksServices {
 private static Logger log = LoggerFactory.getLogger(TasksServices.class);
 @Autowired(required = true)
 RestTemplate rt;
 @Bean
 public RestTemplate rt() {
  return new RestTemplate();
 }
 List<Tasks> getTasksByUserID(int userID) {
  ResponseEntity<Tasks[]> retasks = rt
    .getForEntity("https://jsonplaceholder.typicode.com/users/" + userID + "/todos", Tasks[].class);
  List<Tasks> lt = Arrays.asList(retasks.getBody());
  return lt;
 }
 @Async
 public CompletableFuture<List<Tasks>> getTaks(int userID) throws InterruptedException {
  // Start the clock
  long start = System.currentTimeMillis();
  log.info("Employee:--" + userID + "Started at" + start);
  List<Tasks> lt = this.getTasksByUserID(userID);
  // delay for demo purpose
  Thread.sleep(1000L);
  long end = System.currentTimeMillis();
  log.info("Employee:--" + userID + "end at" + end);
  return CompletableFuture.completedFuture(lt);
 }
}
In the above code you can notice that in line 35 we have used @Async with a public method of CompletableFuture return type, and in line 46 we have invoke completedFuture() method of CompletableFuture by passing TypeMatch ( List<Tasks> ) object as a parameter.Step4: Executing tasks with threads by using ComppletableFuture
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.jai43.jsite.models.Tasks;
import com.jai43.jsite.services.TasksServices;
@RestController
@RequestMapping("/tasks")
public class TasksController {
 long start = System.currentTimeMillis();
 private static Logger log = LoggerFactory.getLogger(TasksController.class);
 @Autowired
 TasksServices ts;
 @GetMapping("/tlist/{uid1}/{uid2}")
 public List<Tasks> getTasksByUserID(@PathVariable(name = "uid1") int uid1, @PathVariable(name = "uid2") int uid2)
   throws InterruptedException, ExecutionException {
  long start = System.currentTimeMillis();
  log.info("started at" + start);
  CompletableFuture<List<Tasks>> ct1 = ts.getTaks(uid1);
  CompletableFuture<List<Tasks>> ct2 = ts.getTaks(uid2);
  CompletableFuture.allOf(ct1, ct2).join();
  List<Tasks> userTList1 = ct1.get();
  List<Tasks> userTList2 = ct2.get();
  List<Tasks> list = new ArrayList<>();
  list.addAll(userTList1);
  list.addAll(userTList2);
  long end = System.currentTimeMillis();
  log.info("End at at" + end);
  return list;
 }
}
In the above code you can see line numbers 35 and 36 where we invoked @Async annotated methods and in line 38 we have added two tasks to CompletableFuture object with join() method. This will let wait until completion of threadpool tasks to proceed further stepOutput with Async enabling
| Executing tasks with Async | 
Output without Aysnc
| Executing tasks without Async | 

 
 
  Posted by: jaya
                      Posted by: jaya 
 
comment from author
ReplyDelete