项目中发现了一个新的玩意WebAsyncTask

开发 项目管理
异步请求的处理。除了异步请求,一般上我们用的比较多的应该是异步调用。通常在开发过程中,会遇到一个方法是和实际业务无关的,没有紧密性的。比如记录日志信息等业务。

[[403136]]

本文转载自微信公众号「六脉神剑的程序人生」,作者六脉神剑小六六。转载本文请联系六脉神剑的程序人生公众号。

絮叨

刚好在读项目代码的时候,发现了WebAsyncTask这个新玩意,给大家来科普科普,不是那么的深入,不喜勿喷!

 

SpringBoot中同异步调用的使用

异步请求的处理。除了异步请求,一般上我们用的比较多的应该是异步调用。通常在开发过程中,会遇到一个方法是和实际业务无关的,没有紧密性的。比如记录日志信息等业务。这个时候正常就是启一个新线程去做一些业务处理,让主线程异步的执行其他业务。

  • 同步请求

  • 异步请求

SprinBoot中@Async异步方法

异步的好处是,可以提高程序吞吐量,一个任务,让耗时的异步处理,并继续同步处理后面的任务,异步任务可以返回结果,拿到结果后可结合同步处理过程中的变量一起处理计算

具体的使用

在Spring中,基于@Async标注的方法,称之为异步方法;这些方法将在执行的时候,将会在独立的线程中被执行,调用者无需等待它的完成,即可继续其他的操作。

自定义线程池异步调用

配置@EnableAsync使@Async生效

@SpringBootApplication 
@EnableAsync 
public class Application { 
  
 public static void main(String[] args) { 
  SpringApplication.run(Application.class, args); 
 } 
  

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.

自定义线程池

@Component 
@Scope  //单例 
public class MyExecutePoll { 
  
    @Bean 
    public Executor myAsyncPool() { 
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); 
        //核心线程池大小 
        executor.setCorePoolSize(20); 
        //最大线程数 
        executor.setMaxPoolSize(40); 
        //队列容量 
        executor.setQueueCapacity(50); 
        // 活跃时间 
        executor.setKeepAliveSeconds(300); 
        // 线程名字前缀 
        executor.setThreadNamePrefix("MyExecutor-"); 
        //设置线程池关闭的时候等待所有任务都完成再继续销毁其他的Bean,使异步线程的销毁优先于Redis等其他处理报错 
        executor.setWaitForTasksToCompleteOnShutdown(true); 
        //设置线程池中任务的等待时间,如果超过这个时候还没有销毁就强制销毁,以确保应用最后能够被关闭,而不是阻塞住 
        executor.setAwaitTerminationSeconds(60); 
        // setRejectedExecutionHandler:当pool已经达到max size的时候,如何处理新任务 
        // CallerRunsPolicy:不在新线程中执行任务,而是由调用者所在的线程来执行 
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); 
        executor.initialize(); 
        return executor; 
    } 
  

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.

使用@Async

@Async("myAsyncPool")   //@Async使用默认的线程 
public Future<String> doTask() throws Exception { 
    //业务处理   使用Future返回异步调用结果 
    return new AsyncResult<>("任务一完成"); 
  • 1.
  • 2.
  • 3.
  • 4.

在Spring中运用 Async注解 需要注意几点:

  • AsyncTest.java,测试类,调用异步任务,同时执行同步方法
  • OrderService.java,异步任务类,提供异步方法
  • AsyncThreadPoolConfig.java,异步任务线程池配置类,配置异步任务运行的线程池大小等

基于Spring实现异步请求

Spring可以通过Callable或者WebAsyncTask等方式实现异步请求, 我们来看看,这2种实现方式!

Callable

Callable是为了异步生成返回值提供基本的支持。简单来说就是一个请求进来,如果你使用了Callable,在没有得到返回数据之前,DispatcherServlet和所有Filter就会退出Servlet容器线程,但响应保持打开状态,一旦返回数据有了,这个DispatcherServlet就会被再次调用并且处理,以异步产生的方式,向请求端返回值。这么做的好处就是请求不会长时间占用服务连接池,提高服务器的吞吐量。

@GetMapping("/callable"
    public Callable<String> testCallable() throws InterruptedException { 
        log.info("主线程开始!"); 
        Callable<String> result = new Callable<String>() { 
 
            @Override 
            public String call() throws Exception { 
                log.info("副线程开始!"); 
                Thread.sleep(1000); 
                log.info("副线程结束!"); 
                return "SUCCESS"
            } 
 
        }; 
        log.info("主线程结束!"); 
        return result; 
    } 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.

输出结果

主线程开始! 
 
主线程结束! 
 
副线程开始! 
 
副线程结束! 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

WebAsyncTask

一个请求到服务上,是用的web容器的线程接收的

我们可以使用WebAsyncTask将这个请求分发给一个新的线程去执行,容器的线程可以去接收其他请求的处理。一旦WebAsyncTask返回数据有了,就会被再次调用并且处理,以异步产生的方式,向请求端返回值,但是其实我觉得前端的请求rt并不会说变短。

/** 
    * 查询 
    */ 
   @RequestMapping(method = RequestMethod.GET, value = "/aysncTask/{testId}"
   @ResponseStatus(HttpStatus.OK) 
   public WebAsyncTask<Response> aysncTask(@PathVariable("testId") String testId) { 
       System.out.println(String.format("/aysncTask/%s 被调用 thread id is: %s", testId,Thread.currentThread().getName())); 
       Callable<Response> callable = () -> { 
           Thread.sleep(1000L); 
           Response response = new Response(true,"异步执行成功"); 
           System.out.println(String.format("/aysncTask/%s 被调用 thread id is: %s", testId,Thread.currentThread().getName())); 
           return response; 
       }; 
       return new WebAsyncTask<Response>(callable); 
   } 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.

控制台打印如下:在执行业务逻辑之前的线程和具体处理业务逻辑的线程不是同一个,达到了我们的目的。async-customize-1这个前缀是我们自定义的下边会说

/aysncTask/12348567676 被调用 thread id is: http-nio-8084-exec-1 
/aysncTask/12348567676 被调用 thread id is: async-customize-1 
  • 1.
  • 2.

其实WebAsyncTask比起Callable是有以下几个优点的

官方有这么一句话,截图给你:

如果我们需要超时处理的回调或者错误处理的回调,我们可以使用WebAsyncTask代替Callable

实际使用中,我并不建议直接使用Callable ,而是使用Spring提供的WebAsyncTask 代替,它包装了Callable,功能更强大些

总结

 

其实本文就是给大家科普下,一些异步的用法,不至于说看到人家这么用很蒙b,多线程的东西还是优点东西的,大家一起学习。

 

责任编辑:武晓燕 来源: 六脉神剑的程序人生
相关推荐

2021-06-17 10:01:54

APT活动Victory 后门恶意软件

2021-01-26 11:16:12

漏洞网络安全网络攻击

2022-04-28 09:41:29

Linux 操作系统漏洞Microsoft

2021-10-29 11:45:26

Python代码Python 3.

2022-11-30 09:18:51

JavaMyBatisMQ

2023-02-26 01:02:22

2021-04-22 07:47:47

JavaJDKMYSQL

2021-12-29 19:20:41

数据GitHub服务器

2021-06-09 18:59:48

AI

2021-06-09 14:45:50

安全漏洞攻击漏洞

2021-03-06 13:31:52

网络钓鱼恶意邮件攻击

2024-05-20 08:25:55

2019-01-14 11:10:43

机器学习人工智能计算机

2020-06-09 08:05:11

Android 代码操作系统

2023-05-17 00:22:15

2021-03-08 10:58:03

漏洞Microsoft E微软

2021-04-28 14:31:35

Dubbo接口日志

2020-06-16 08:39:35

JavaScript图像处理库

2021-04-08 15:30:14

谷歌Android开发者

2020-05-18 08:42:23

CSS背景图像前端开发
点赞
收藏

51CTO技术栈公众号