Springboot集成定时器和多线程异步处理

需求:用@schedule标签进行定时处理逻辑,由于业务处理速度慢,需要每次执行逻辑放在不同的线程里异步执行

springboot集成多线程异步,直接上配置:

/**
 * 线程池异步配置
 */

@Configuration
@EnableAsync
public class ThreadExecutorConfig
        implements AsyncConfigurer {


    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 设置核心线程数
        executor.setCorePoolSize(5);
        // 设置最大线程数
        executor.setMaxPoolSize(7);
        // 设置队列容量
        executor.setQueueCapacity(20);
        // 设置线程活跃时间(秒)
        executor.setKeepAliveSeconds(60);
        // 设置默认线程名称
        executor.setThreadNamePrefix("PASCAL-");
        // 设置拒绝策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 等待所有任务结束后再关闭线程池
        executor.setWaitForTasksToCompleteOnShutdown(true);
        executor.initialize();
        return executor;
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return new MyAsyncUncaughtExceptionHandler();
    }
}

 下面的是对多线程异步的时候报出的异常处理方法,可以自定义一个处理多线程异常类来实现自身的业务逻辑.

import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;

import java.lang.reflect.Method;

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

            // handle exception
    }
}

 

启动类上要记得添加异步和开启定时器的标签

@SpringBootApplication
@EnableScheduling
@Async
public class MultithreadingApplication {

    public static void main(String[] args) {
        SpringApplication.run(MultithreadingApplication.class, args);
    }

}

 业务逻辑方法:

    @Async
    @Scheduled(initialDelay=1000,fixedDelay = 5000)
    public void test(){
        SimpleDateFormat format=new SimpleDateFormat("HH:mm:ss");
        try {
            logger.info("当前线程为:"+Thread.currentThread().getName()+",方法开始时间为:"+format.format(new Date()));
            Thread.sleep(10000);
            logger.info("当前线程为:"+Thread.currentThread().getName()+",方法结束时间为:"+format.format(new Date()));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

对于@Schedule注解的使用方法:

点进去可以看到有几个可选参数:

  • fixedDelay:控制方法执行的间隔时间,是以上一次方法执行完开始算起,如上一次方法执行阻塞住了,那么直到上一次执行完,并间隔给定的时间后,执行下一次
  • fixedRate:是按照一定的速率执行,是从上一次方法执行开始的时间算起,如果上一次方法阻塞住了,下一次也是不会执行,但是在阻塞这段时间内累计应该执行的次数,当不再阻塞时,一下子把这些全部执行掉,而后再按照固定速率继续执行。
  • initialDelay:如: @Scheduled(initialDelay = 10000,fixedRate = 15000
    这个定时器就是在上一个的基础上加了一个initialDelay = 10000 意思就是在容器启动后,延迟10秒后再执行一次定时器,以后每15秒再执行一次该定时器.
  • cron表达式可以定制化执行任务,但是执行的方式是与fixedDelay相近的,也是会按照上一次方法结束时间开始算起。

这里可以根据自身的业务需求,看到底选择哪一个更适合,这里cron表达式就不再多言,可以结合自身应用场景来定

这样,需求就实现了

测试结果:

20-07-07 11:12:40.436  INFO 32360 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8081 (http) with context path ''
2020-07-07 11:12:40.444  INFO 32360 --- [           main] c.e.m.MultithreadingApplication          : Started MultithreadingApplication in 1.223 seconds (JVM running for 1.739)
2020-07-07 11:12:41.445  INFO 32360 --- [   scheduling-1] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService
2020-07-07 11:12:41.452  INFO 32360 --- [       PASCAL-1] c.e.multithreading.service.TestService   : 当前线程为:PASCAL-1,方法开始时间为:11:12:41
2020-07-07 11:12:46.448  INFO 32360 --- [       PASCAL-2] c.e.multithreading.service.TestService   : 当前线程为:PASCAL-2,方法开始时间为:11:12:46
2020-07-07 11:12:51.450  INFO 32360 --- [       PASCAL-3] c.e.multithreading.service.TestService   : 当前线程为:PASCAL-3,方法开始时间为:11:12:51
2020-07-07 11:12:51.453  INFO 32360 --- [       PASCAL-1] c.e.multithreading.service.TestService   : 当前线程为:PASCAL-1,方法结束时间为:11:12:51
2020-07-07 11:12:56.449  INFO 32360 --- [       PASCAL-2] c.e.multithreading.service.TestService   : 当前线程为:PASCAL-2,方法结束时间为:11:12:56
2020-07-07 11:12:56.450  INFO 32360 --- [       PASCAL-4] c.e.multithreading.service.TestService   : 当前线程为:PASCAL-4,方法开始时间为:11:12:56
2020-07-07 11:13:01.450  INFO 32360 --- [       PASCAL-3] c.e.multithreading.service.TestService   : 当前线程为:PASCAL-3,方法结束时间为:11:13:01
2020-07-07 11:13:01.452  INFO 32360 --- [       PASCAL-5] c.e.multithreading.service.TestService   : 当前线程为:PASCAL-5,方法开始时间为:11:13:01
2020-07-07 11:13:06.451  INFO 32360 --- [       PASCAL-4] c.e.multithreading.service.TestService   : 当前线程为:PASCAL-4,方法结束时间为:11:13:06
2020-07-07 11:13:06.453  INFO 32360 --- [       PASCAL-1] c.e.multithreading.service.TestService   : 当前线程为:PASCAL-1,方法开始时间为:11:13:06
2020-07-07 11:13:11.453  INFO 32360 --- [       PASCAL-5] c.e.multithreading.service.TestService   : 当前线程为:PASCAL-5,方法结束时间为:11:13:11
2020-07-07 11:13:11.455  INFO 32360 --- [       PASCAL-2] c.e.multithreading.service.TestService   : 当前线程为:PASCAL-2,方法开始时间为:11:13:11
2020-07-07 11:13:16.453  INFO 32360 --- [       PASCAL-1] c.e.multithreading.service.TestService   : 当前线程为:PASCAL-1,方法结束时间为:11:13:16
2020-07-07 11:13:16.455  INFO 32360 --- [       PASCAL-3] c.e.multithreading.service.TestService   : 当前线程为:PASCAL-3,方法开始时间为:11:13:16
2020-07-07 11:13:21.456  INFO 32360 --- [       PASCAL-2] c.e.multithreading.service.TestService   : 当前线程为:PASCAL-2,方法结束时间为:11:13:21
2020-07-07 11:13:21.457  INFO 32360 --- [       PASCAL-4] c.e.multithreading.service.TestService   : 当前线程为:PASCAL-4,方法开始时间为:11:13:21
2020-07-07 11:13:26.456  INFO 32360 --- [       PASCAL-3] c.e.multithreading.service.TestService   : 当前线程为:PASCAL-3,方法结束时间为:11:13:26
2020-07-07 11:13:26.457  INFO 32360 --- [       PASCAL-5] c.e.multithreading.service.TestService   : 当前线程为:PASCAL-5,方法开始时间为:11:13:26
2020-07-07 11:13:31.458  INFO 32360 --- [       PASCAL-4] c.e.multithreading.service.TestService   : 当前线程为:PASCAL-4,方法结束时间为:11:13:31
2020-07-07 11:13:31.459  INFO 32360 --- [       PASCAL-1] c.e.multithreading.service.TestService   : 当前线程为:PASCAL-1,方法开始时间为:11:13:31
2020-07-07 11:13:36.458  INFO 32360 --- [       PASCAL-5] c.e.multithreading.service.TestService   : 当前线程为:PASCAL-5,方法结束时间为:11:13:36
2020-07-07 11:13:36.460  INFO 32360 --- [       PASCAL-2] c.e.multithreading.service.TestService   : 当前线程为:PASCAL-2,方法开始时间为:11:13:36
2020-07-07 11:13:41.459  INFO 32360 --- [       PASCAL-1] c.e.multithreading.service.TestService   : 当前线程为:PASCAL-1,方法结束时间为:11:13:41
2020-07-07 11:13:41.462  INFO 32360 --- [       PASCAL-3] c.e.multithreading.service.TestService   : 当前线程为:PASCAL-3,方法开始时间为:11:13:41
2020-07-07 11:13:46.461  INFO 32360 --- [       PASCAL-2] c.e.multithreading.service.TestService   : 当前线程为:PASCAL-2,方法结束时间为:11:13:46

 

每隔五秒执行一次

----------------------------------------------------------------------------分割线------------------------------------------------------------------------------------

如果有多个定时任务,每个任务需要在不同的线程间处理的话,就要用另外的配置:如下:

/**
 * 配置多个schedule的线程配置
 */
@Configuration
@EnableScheduling
public class ScheduleConfig implements SchedulingConfigurer{
    /*
     * 并行任务
     */
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar)
    {
        ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
        taskScheduler.setThreadNamePrefix("Schedule-Task-");
        taskScheduler.setPoolSize(5);
        taskScheduler.setAwaitTerminationSeconds(60);
        taskScheduler.setWaitForTasksToCompleteOnShutdown(true);
        taskScheduler.initialize();
        taskRegistrar.setTaskScheduler(taskScheduler);
    }
}

业务如下:

    @Scheduled(cron = "*/5 * * * * ?")
    public void test1(){
        SimpleDateFormat format=new SimpleDateFormat("HH:mm:ss");
        try {
            logger.info("当前线程为:"+Thread.currentThread().getName()+",方法开始时间为:"+format.format(new Date()));
            Thread.sleep(10000);
            logger.info("当前线程为:"+Thread.currentThread().getName()+",方法结束时间为:"+format.format(new Date()));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Scheduled(cron = "*/5 * * * * ?")
    public void test2(){
        SimpleDateFormat format=new SimpleDateFormat("HH:mm:ss");
        try {
            logger.info("当前线程为:"+Thread.currentThread().getName()+",方法开始时间为:"+format.format(new Date()));
            Thread.sleep(10000);
            logger.info("当前线程为:"+Thread.currentThread().getName()+",方法结束时间为:"+format.format(new Date()));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

测试结果:

2020-07-07 11:34:53.101  INFO 27440 --- [           main] c.e.m.MultithreadingApplication          : Started MultithreadingApplication in 1.147 seconds (JVM running for 1.74)
2020-07-07 11:34:55.002  INFO 27440 --- [Schedule-Task-2] c.e.multithreading.service.TestService   : 当前线程为:Schedule-Task-2,方法开始时间为:11:34:55
2020-07-07 11:34:55.002  INFO 27440 --- [Schedule-Task-1] c.e.multithreading.service.TestService   : 当前线程为:Schedule-Task-1,方法开始时间为:11:34:55
2020-07-07 11:35:05.003  INFO 27440 --- [Schedule-Task-2] c.e.multithreading.service.TestService   : 当前线程为:Schedule-Task-2,方法结束时间为:11:35:05
2020-07-07 11:35:05.003  INFO 27440 --- [Schedule-Task-1] c.e.multithreading.service.TestService   : 当前线程为:Schedule-Task-1,方法结束时间为:11:35:05
2020-07-07 11:35:10.001  INFO 27440 --- [Schedule-Task-2] c.e.multithreading.service.TestService   : 当前线程为:Schedule-Task-2,方法开始时间为:11:35:10
2020-07-07 11:35:10.001  INFO 27440 --- [Schedule-Task-1] c.e.multithreading.service.TestService   : 当前线程为:Schedule-Task-1,方法开始时间为:11:35:10
2020-07-07 11:35:20.001  INFO 27440 --- [Schedule-Task-2] c.e.multithreading.service.TestService   : 当前线程为:Schedule-Task-2,方法结束时间为:11:35:20
2020-07-07 11:35:20.002  INFO 27440 --- [Schedule-Task-1] c.e.multithreading.service.TestService   : 当前线程为:Schedule-Task-1,方法结束时间为:11:35:20
2020-07-07 11:35:25.001  INFO 27440 --- [Schedule-Task-1] c.e.multithreading.service.TestService   : 当前线程为:Schedule-Task-1,方法开始时间为:11:35:25
2020-07-07 11:35:25.003  INFO 27440 --- [Schedule-Task-3] c.e.multithreading.service.TestService   : 当前线程为:Schedule-Task-3,方法开始时间为:11:35:25
2020-07-07 11:35:35.001  INFO 27440 --- [Schedule-Task-1] c.e.multithreading.service.TestService   : 当前线程为:Schedule-Task-1,方法结束时间为:11:35:35
2020-07-07 11:35:35.003  INFO 27440 --- [Schedule-Task-3] c.e.multithreading.service.TestService   : 当前线程为:Schedule-Task-3,方法结束时间为:11:35:35
2020-07-07 11:35:40.002  INFO 27440 --- [Schedule-Task-1] c.e.multithreading.service.TestService   : 当前线程为:Schedule-Task-1,方法开始时间为:11:35:40
2020-07-07 11:35:40.002  INFO 27440 --- [Schedule-Task-5] c.e.multithreading.service.TestService   : 当前线程为:Schedule-Task-5,方法开始时间为:11:35:40
2020-07-07 11:35:50.002  INFO 27440 --- [Schedule-Task-1] c.e.multithreading.service.TestService   : 当前线程为:Schedule-Task-1,方法结束时间为:11:35:50
2020-07-07 11:35:50.002  INFO 27440 --- [Schedule-Task-5] c.e.multithreading.service.TestService   : 当前线程为:Schedule-Task-5,方法结束时间为:11:35:50

 

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值