@Async异步调用 —— 多线程分享(一)

@Async异步调用

项目中实现异步调用的方式还是挺多的,大多要么是使用ExecutorService要么是使用@Async注解,要么干脆直接手动创建线程。之前我自己都是使用ExecutorService去实现多线程的业务操作,但是奈何阿里巴巴归约扫描,看着难受。不用@Async不就是图个懒得写配置省事的。另外其中各自的优缺点这里就不再赘述了,本身也就是记录下自己使用的业务背景和代码配置情况吧。

业务背景: 实现的功能是Excel数据导入到数据库,由于使用的是SpringCloud,都是服务间的调用。所以基本的操作就是A服务接收上传的数据整理成业务参数后,调用B服务去进行落入数据库的操作。因为数据量较大,B服务无法在规定的超时时间内给予A服务响应,导致调用异常。故此考虑将数据平均分组,使用多线程异步去解决,同时在B服务内也使用多线程去进行数据库插入操作(后来改成了批量插入,效率更好,减少了数据库频繁访问连接的开销)。

代码:
@Bean(“taskExecutorOne”) :将配置的策略实例化,并命名,交给容器去管理。用的时候直接指定名字就可以了。

这里针对不同的业务场景,配置不同的策略,看自己的实际需求吧。

@EnableAsync
@Configuration
public class TaskPoolConfig {

    @Bean("taskExecutorOne")
    public Executor taskExecutorOne() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //核心线程数10:线程池创建时候初始化的线程数
        executor.setCorePoolSize(10);
        //最大线程数20:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
        executor.setMaxPoolSize(20);
        //缓冲队列200:用来缓冲执行任务的队列
        executor.setQueueCapacity(200);
        //允许线程的空闲时间60秒:当超过了核心线程出之外的线程在空闲时间到达之后会被销毁
        executor.setKeepAliveSeconds(60);
        //线程池名的前缀:设置好了之后可以方便我们定位处理任务所在的线程池
        executor.setThreadNamePrefix("taskExecutorOne-");
        /* 线程池对拒绝任务的处理策略:这里采用了CallerRunsPolicy策略,
        当线程池没有处理能力的时候,该策略会直接在 execute 方法的调用线程中运行被拒绝的任务;
         如果执行程序已关闭,则会丢弃该任务 */
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        /* 说明:setWaitForTasksToCompleteOnShutdown(true)该方法就是这里的关键,
         用来设置线程池关闭的时候等待所有任务都完成再继续销毁其他的Bean,
         这样这些异步任务的销毁就会先于Redis线程池的销毁。同时,
         这里还设置了setAwaitTerminationSeconds(60),该方法用来设置线程池中任务的等待时间,
         如果超过这个时候还没有销毁就强制销毁,以确保应用最后能够被关闭,而不是阻塞住。 */
        executor.setWaitForTasksToCompleteOnShutdown(true);
        executor.setAwaitTerminationSeconds(60);
        return executor;
    }

    @Bean("taskExecutorTwo")
    public Executor taskExecutorTwo() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //核心线程数10:线程池创建时候初始化的线程数
        executor.setCorePoolSize(10);
        //最大线程数20:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
        executor.setMaxPoolSize(50);
        //缓冲队列200:用来缓冲执行任务的队列
        executor.setQueueCapacity(200);
        //允许线程的空闲时间60秒:当超过了核心线程出之外的线程在空闲时间到达之后会被销毁
        executor.setKeepAliveSeconds(60);
        //线程池名的前缀:设置好了之后可以方便我们定位处理任务所在的线程池
        executor.setThreadNamePrefix("taskExecutorTwo-");
        /* 线程池对拒绝任务的处理策略:这里采用了CallerRunsPolicy策略,
        当线程池没有处理能力的时候,该策略会直接在 execute 方法的调用线程中运行被拒绝的任务;
         如果执行程序已关闭,则会丢弃该任务 */
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        /* 说明:setWaitForTasksToCompleteOnShutdown(true)该方法就是这里的关键,
         用来设置线程池关闭的时候等待所有任务都完成再继续销毁其他的Bean,
         这样这些异步任务的销毁就会先于Redis线程池的销毁。同时,
         这里还设置了setAwaitTerminationSeconds(60),该方法用来设置线程池中任务的等待时间,
         如果超过这个时候还没有销毁就强制销毁,以确保应用最后能够被关闭,而不是阻塞住。 */
        executor.setWaitForTasksToCompleteOnShutdown(true);
        executor.setAwaitTerminationSeconds(60);
        return executor;
    }

    @Bean("taskExecutorThree")
    public Executor taskExecutorThree() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //核心线程数10:线程池创建时候初始化的线程数
        executor.setCorePoolSize(10);
        //最大线程数20:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
        executor.setMaxPoolSize(20);
        //缓冲队列200:用来缓冲执行任务的队列
        executor.setQueueCapacity(200);
        //允许线程的空闲时间60秒:当超过了核心线程出之外的线程在空闲时间到达之后会被销毁
        executor.setKeepAliveSeconds(60);
        //线程池名的前缀:设置好了之后可以方便我们定位处理任务所在的线程池
        executor.setThreadNamePrefix("taskExecutorThree-");
        /* 线程池对拒绝任务的处理策略:这里采用了CallerRunsPolicy策略,
        当线程池没有处理能力的时候,该策略会直接在 execute 方法的调用线程中运行被拒绝的任务;
         如果执行程序已关闭,则会丢弃该任务 */
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        /* 说明:setWaitForTasksToCompleteOnShutdown(true)该方法就是这里的关键,
         用来设置线程池关闭的时候等待所有任务都完成再继续销毁其他的Bean,
         这样这些异步任务的销毁就会先于Redis线程池的销毁。同时,
         这里还设置了setAwaitTerminationSeconds(60),该方法用来设置线程池中任务的等待时间,
         如果超过这个时候还没有销毁就强制销毁,以确保应用最后能够被关闭,而不是阻塞住。 */
        executor.setWaitForTasksToCompleteOnShutdown(true);
        executor.setAwaitTerminationSeconds(60);
        return executor;
    }

    @Bean("taskExecutorFour")
    public Executor taskExecutorFour() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //核心线程数10:线程池创建时候初始化的线程数
        executor.setCorePoolSize(10);
        //最大线程数20:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
        executor.setMaxPoolSize(20);
        //缓冲队列200:用来缓冲执行任务的队列
        executor.setQueueCapacity(200);
        //允许线程的空闲时间60秒:当超过了核心线程出之外的线程在空闲时间到达之后会被销毁
        executor.setKeepAliveSeconds(60);
        //线程池名的前缀:设置好了之后可以方便我们定位处理任务所在的线程池
        executor.setThreadNamePrefix("taskExecutorFour-");
        /* 线程池对拒绝任务的处理策略:这里采用了CallerRunsPolicy策略,
        当线程池没有处理能力的时候,该策略会直接在 execute 方法的调用线程中运行被拒绝的任务;
         如果执行程序已关闭,则会丢弃该任务 */
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        /* 说明:setWaitForTasksToCompleteOnShutdown(true)该方法就是这里的关键,
         用来设置线程池关闭的时候等待所有任务都完成再继续销毁其他的Bean,
         这样这些异步任务的销毁就会先于Redis线程池的销毁。同时,
         这里还设置了setAwaitTerminationSeconds(60),该方法用来设置线程池中任务的等待时间,
         如果超过这个时候还没有销毁就强制销毁,以确保应用最后能够被关闭,而不是阻塞住。 */
        executor.setWaitForTasksToCompleteOnShutdown(true);
        executor.setAwaitTerminationSeconds(60);
        return executor;
    }

    @Bean("taskExecutorFive")
    public Executor taskExecutorFive() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //核心线程数10:线程池创建时候初始化的线程数
        executor.setCorePoolSize(10);
        //最大线程数20:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
        executor.setMaxPoolSize(20);
        //缓冲队列200:用来缓冲执行任务的队列
        executor.setQueueCapacity(200);
        //允许线程的空闲时间60秒:当超过了核心线程出之外的线程在空闲时间到达之后会被销毁
        executor.setKeepAliveSeconds(60);
        //线程池名的前缀:设置好了之后可以方便我们定位处理任务所在的线程池
        executor.setThreadNamePrefix("taskExecutorFive-");
        /* 线程池对拒绝任务的处理策略:这里采用了CallerRunsPolicy策略,
        当线程池没有处理能力的时候,该策略会直接在 execute 方法的调用线程中运行被拒绝的任务;
         如果执行程序已关闭,则会丢弃该任务 */
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        /* 说明:setWaitForTasksToCompleteOnShutdown(true)该方法就是这里的关键,
         用来设置线程池关闭的时候等待所有任务都完成再继续销毁其他的Bean,
         这样这些异步任务的销毁就会先于Redis线程池的销毁。同时,
         这里还设置了setAwaitTerminationSeconds(60),该方法用来设置线程池中任务的等待时间,
         如果超过这个时候还没有销毁就强制销毁,以确保应用最后能够被关闭,而不是阻塞住。 */
        executor.setWaitForTasksToCompleteOnShutdown(true);
        executor.setAwaitTerminationSeconds(60);
        return executor;
    }
}

这里在插入数据库的方法上添加@Async注解,注解内指定要使用策略的实例的名称即可。

 @Async("taskExecutorOne")
    public void addData(User user) {
        userMapper.insert(user);
    }

如有错误,还请指正~

你可能感兴趣的:(java)