zoukankan      html  css  js  c++  java
  • Spring Boot @Async 异步任务执行

    1、任务执行和调度

    SpringTaskExecutorTaskScheduler接口提供了异步执行和调度任务的抽象。

    SpringTaskExecutorjava.util.concurrent.Executor接口时一样的,这个接口只有一个方法execute(Runnable task)

    1.1、TaskExecutor类型

    Spring已经内置了许多TaskExecutor的实现,你没有必要自己去实现:

    • SimpleAsyncTaskExecutor  这种实现不会重用任何线程,每次调用都会创建一个新的线程。
    • SyncTaskExecutor  这种实现不会异步的执行
    • ConcurrentTaskExecutor  这种实现是java.util.concurrent.Executor的一个adapter
    • SimpleThreadPoolTaskExecutor  这种实现实际上是Quartz的SimpleThreadPool的一个子类,它监听Spring的声明周期回调。
    • ThreadPoolTaskExecutor  这是最常用最通用的一种实现。它包含了java.util.concurrent.ThreadPoolExecutor的属性,并且用TaskExecutor进行包装。

    1.2、注解支持调度和异步执行

    To enable support for @Scheduled and @Async annotations add @EnableScheduling and @EnableAsync to one of your @Configuration classes:

    @Configuration
    @EnableAsync
    @EnableScheduling
    public class AppConfig {
    }

    特别注意

    The default advice mode for processing @Async annotations is "proxy" which allows for interception of calls through the proxy only; local calls within the same class cannot get intercepted that way. For a more advanced mode of interception, consider switching to "aspectj" mode in combination with compile-time or load-time weaving.

    默认是用代理去处理@Async的,因此,相同类中的方法调用带@Async的方法是无法异步的,这种情况仍然是同步。

    举个例子:下面这种,在外部直接调用sayHi()是可以异步执行的,而调用sayHello()时sayHi()仍然是同步执行

    public class A {
      
        public void sayHello() {
            sayHi();
        }
    
        @Async
        public void sayHi() {
    
        }   
      
    }

    1.3、@Async注解

    在方法上加@Async注解表示这是一个异步调用。换句话说,方法的调用者会立即得到返回,并且实际的方法执行是想Spring的TaskExecutor提交了一个任务。

    In other words, the caller will return immediately upon invocation and the actual execution of the method will occur in a task that has been submitted to a Spring TaskExecutor.

    @Async
    void doSomething() {
        // this will be executed asynchronously
    }
    @Async
    void doSomething(String s) {
        // this will be executed asynchronously
    }
    @Async
    Future<String> returnSomething(int i) {
        // this will be executed asynchronously
    }

    注意:

    @Async methods may not only declare a regular java.util.concurrent.Future return type but also Spring’s org.springframework.util.concurrent.ListenableFuture or, as of Spring 4.2, JDK 8’s java.util.concurrent.CompletableFuture: for richer interaction with the asynchronous task and for immediate composition with further processing steps.

    1.4、@Async限定Executor

    默认情况下,当在方法上加@Async注解时,将会使用一个支持注解驱动的Executor。然而,@Async注解的value值可以指定一个别的Executor

    @Async("otherExecutor")
    void doSomething(String s) {
        // this will be executed asynchronously by "otherExecutor"
    }

    这里,otherExecutor是Spring容器中任意Executor bean的名字。

    1.5、@Async异常管理

    当一个@Async方法有一个Future类型的返回值时,就很容易管理在调Future的get()方法获取任务的执行结果时抛出的异常。如果返回类型是void,那么异常是不会被捕获到的。

    public class MyAsyncUncaughtExceptionHandler implements AsyncUncaughtExceptionHandler {
    
        @Override
        public void handleUncaughtException(Throwable ex, Method method, Object... params) {
            // handle exception
        }
    }

     2、线程池配置

     1
     3 import org.springframework.context.annotation.Bean;
     4 import org.springframework.context.annotation.Configuration;
     5 import org.springframework.scheduling.annotation.EnableAsync;
     6 import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
     7 
     8 @Configuration
     9 @EnableAsync
    10 public class TaskExecutorConfig {
    11 
    12     private Integer corePoolSize = 30;
    13 
    14     private Integer maxPoolSize = 50;
    15 
    16     private Integer keepAliveSeconds = 300;
    17 
    18 //    private Integer queueCapacity = 2000;
    19 
    20     @Bean("myThreadPoolTaskExecutor")
    21     public ThreadPoolTaskExecutor myThreadPoolTaskExecutor() {
    22         ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
    23         executor.setCorePoolSize(corePoolSize);
    24         executor.setMaxPoolSize(maxPoolSize);
    25         executor.setKeepAliveSeconds(keepAliveSeconds);
    26 //        executor.setQueueCapacity(queueCapacity);
    27         executor.setWaitForTasksToCompleteOnShutdown(true);
    28         executor.initialize();
    29         return executor;
    30     }
    31 
    32 }

    调用

     1     @Async("myThreadPoolTaskExecutor")
     2     @Override
     3     public void present(CouponPresentLogEntity entity) {
     4         try {
     5             CouponBaseResponse rst = couponSendRpcService.send(entity.getUserId(), entity.getCouponBatchKey(), "1", entity.getVendorId());
     6             if (null != rst && rst.isSuccess()) {
     7                 entity.setStatus(PresentStatusEnum.SUCCESS.getType());
     8             }else {
     9                 String reason = (null == rst) ? "响应异常" : rst.getMsg();
    10                 entity.setFailureReason(reason);
    11                 entity.setStatus(PresentStatusEnum.FAILURE.getType());
    12             }
    13         }catch (Exception ex) {
    14             log.error(ex.getMessage(), ex);
    15             entity.setFailureReason(ex.getMessage());
    16             entity.setStatus(PresentStatusEnum.FAILURE.getType());
    17         }
    18         couponPresentLogDao.update(entity);
    19     }

    结果

    [INFO ] 2018-05-09 16:27:39.887 [myThreadPoolTaskExecutor-1] [com.ourhours.coupon.rpc.dubbo.ReceiveLogFilter] - receive method-name:send; arguments:[10046031,"4d7cc32f8f7e4b00bca56f6bf4b3b658","1",10001]
    [INFO ] 2018-05-09 16:27:39.889 [myThreadPoolTaskExecutor-2] [com.ourhours.coupon.rpc.dubbo.ReceiveLogFilter] - receive method-name:send; arguments:[10046031,"4d7cc32f8f7e4b00bca56f6bf4b3b658","1",10001]

     参考:

    Spring Framework Reference Documentation 4.3.17.RELEASE

     

  • 相关阅读:
    5、python中的列表
    Linux---配置新服务器的常见操作(CentOS7)
    MapReduce原理篇
    用MR实现Join逻辑的两种方法
    Linux静态库与共享库
    mysql命令查看表结构及注释
    mysql 数据同步到 elastsearch7 数字类型精度丢失
    canal client-adapter 将mysql数据同步到 es elasticsearch 日期时间少8小时问题解决
    如何用redis做活跃用户统计-HyperLoglog
    jvm 虚拟机内存布局
  • 原文地址:https://www.cnblogs.com/cjsblog/p/9016657.html
Copyright © 2011-2022 走看看