SpringBoot异步编程

异步调用:当咱们执行一个方法时,假如这个方法中有多个耗时的任务须要同时去作,并且又不着急等待这个结果时可让客户端当即返回而后,后台慢慢去计算任务。固然你也能够选择等这些任务都执行完了,再返回给客户端。java

SpringBoot 异步编程实战

若是咱们须要在 SpringBoot 实现异步编程的话,经过 Spring 提供的两个注解会让这件事情变的很是简单。web

  1. @EnableAsync:经过在配置类或者Main类上加@EnableAsync开启对异步方法的支持。
  2. @Async 能够做用在类上或者方法上,做用在类上表明这个类的全部方法都是异步方法。

1. 自定义 TaskExecutor

不少人对于 TaskExecutor 不是太了解,因此咱们花一点篇幅先介绍一下这个东西。从名字就能看出它是任务的执行者,它领导执行着线程来处理任务,就像司令官同样,而咱们的线程就比如一只只军队同样,这些军队能够异步对敌人进行打击👊。spring

Spring 提供了TaskExecutor接口做为任务执行者的抽象,它和java.util.concurrent包下的Executor接口很像。稍微不一样的 TaskExecutor接口用到了 Java 8 的语法@FunctionalInterface声明这个接口是一个函数式接口。编程

 

 

 若是没有自定义Executor, Spring 将建立一个 SimpleAsyncTaskExecutor 并使用它。springboot

 1 package com.test.configure;
 2 
 3 import org.springframework.context.annotation.Bean;
 4 import org.springframework.context.annotation.Configuration;
 5 import org.springframework.scheduling.annotation.AsyncConfigurer;
 6 import org.springframework.scheduling.annotation.EnableAsync;
 7 import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
 8 
 9 import java.util.concurrent.Executor;
10 import java.util.concurrent.ThreadPoolExecutor;
11 
12 @Configuration
13 @EnableAsync
14 public class AsyncConfig implements AsyncConfigurer {
15 
16     private static final int CORE_POOL_SIZE = 6;
17     private static final int MAX_POOL_SIZE = 10;
18     private static final int QUEUE_CAPACITY = 100;
19 
20     @Bean
21     public Executor taskExecutor() {
22         // Spring 默认配置是核心线程数大小为1,最大线程容量大小不受限制,队列容量也不受限制。
23         ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
24         // 核心线程数
25         executor.setCorePoolSize(CORE_POOL_SIZE);
26         // 最大线程数
27         executor.setMaxPoolSize(MAX_POOL_SIZE);
28         // 队列大小
29         executor.setQueueCapacity(QUEUE_CAPACITY);
30         // 当最大池已满时,此策略保证不会丢失任务请求,可是可能会影响应用程序总体性能。
31         executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
32         executor.setThreadNamePrefix("My ThreadPoolTaskExecutor-");
33         executor.initialize();
34         return executor;
35     }
36 }

 

Spring 默认使用的是 ThreadPoolExecutor.AbortPolicy。在Spring的默认状况下,ThreadPoolExecutor 将抛出 RejectedExecutionException 来拒绝新来的任务 ,这表明你将丢失对这个任务的处理。 对于可伸缩的应用程序,建议使用 ThreadPoolExecutor.CallerRunsPolicy。当最大池被填满时,此策略为咱们提供可伸缩队列。app

ThreadPoolTaskExecutor 饱和策略定义:异步

若是当前同时运行的线程数量达到最大线程数量时,ThreadPoolTaskExecutor 定义一些策略:async

  • ThreadPoolExecutor.AbortPolicy:抛出 RejectedExecutionException来拒绝新任务的处理。
  • ThreadPoolExecutor.CallerRunsPolicy:调用执行本身的线程运行任务。您不会任务请求。可是这种策略会下降对于新任务提交速度,影响程序的总体性能。另外,这个策略喜欢增长队列容量。若是您的应用程序能够承受此延迟而且你不能任务丢弃任何一个任务请求的话,你能够选择这个策略。
  • ThreadPoolExecutor.DiscardPolicy: 不处理新任务,直接丢弃掉。
  • ThreadPoolExecutor.DiscardOldestPolicy: 此策略将丢弃最先的未处理的任务请求。

2. 编写一个异步的方法

 1 package com.test.service;
 2 
 3 import org.springframework.scheduling.annotation.Async;
 4 import org.springframework.stereotype.Service;
 5 
 6 import java.text.SimpleDateFormat;
 7 import java.util.Date;
 8 
 9 @Service
10 public class AsyncService {
11 
12     @Async
13     public void test() {
14         SimpleDateFormat sdf = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss");
15         String start = sdf.format(new Date());
16         try {
17             Thread.sleep(3000);
18         } catch (InterruptedException e) {
19             e.printStackTrace();
20         }
21         System.out.println("startTime --->" +start + "EndTime --->" +  sdf.format(new Date()));
22     }
23 }

 

 

3. 测试编写的异步方法

 1 package com.test.async.controller;
 2 
 3 import com.test.service.AsyncService;
 4 import org.springframework.beans.factory.annotation.Autowired;
 5 import org.springframework.scheduling.annotation.Async;
 6 import org.springframework.web.bind.annotation.RequestMapping;
 7 import org.springframework.web.bind.annotation.RestController;
 8 
 9 import java.util.HashMap;
10 
11 @RestController
12 @RequestMapping(value = "/async")
13 public class AsyncController {
14 
15     @Autowired
16     private AsyncService asyncService;
17 
18 
19     @RequestMapping(value = "/test")
20     public HashMap<String,String> test() {
21         HashMap<String,String> map = new HashMap<>();
22         map.put("name","libai");
23         asyncService.test();
24         return map;
25     }
26 }

 

测试结果:异步编程

startTime --->2019-10-28 16:34:48   EndTime --->2019-10-28 16:34:51
startTime --->2019-10-28 16:34:48   EndTime --->2019-10-28 16:34:51
startTime --->2019-10-28 16:34:48   EndTime --->2019-10-28 16:34:51
startTime --->2019-10-28 16:34:57   EndTime --->2019-10-28 16:35:00
startTime --->2019-10-28 16:34:57   EndTime --->2019-10-28 16:35:00

 

请求会当即返回,而控制台的输出会在3秒以后输出。函数

相关文章
相关标签/搜索