服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Java教程 - Springboot集成定时器和多线程异步处理操作

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

2020-10-01 00:57PascalLee Java教程

这篇文章主要介绍了Springboot集成定时器和多线程异步处理操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧

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

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

?
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
30
31
32
33
34
35
/**
 * 线程池异步配置
 */
 
@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();
  }
}

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

?
1
2
3
4
5
6
7
8
9
10
11
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
  }
}

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

?
1
2
3
4
5
6
7
8
9
@SpringBootApplication
@EnableScheduling
@Async
public class MultithreadingApplication {
 
  public static void main(String[] args) {
    SpringApplication.run(MultithreadingApplication.class, args);
  }
}

业务逻辑方法:

?
1
2
3
4
5
6
7
8
9
10
11
12
@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表达式就不再多言,可以结合自身应用场景来定

这样,需求就实现了

测试结果:

?
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
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

每隔五秒执行一次

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

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
 * 配置多个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);
  }
}

业务如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@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();
  }
}

测试结果:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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

以上这篇Springboot集成定时器和多线程异步处理操作就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持服务器之家。

原文链接:https://blog.csdn.net/weixin_43469563/article/details/107176629

延伸 · 阅读

精彩推荐
  • Java教程Spring 6.0 将停止支持 Freemarker 和 JSP

    Spring 6.0 将停止支持 Freemarker 和 JSP

    Spring Framework 6.0 第一个里程碑版本已经发布,目前已经可以从Spring Repo获取。这里有一些新变更我们可以提前了解一下。...

    码农小胖哥12642021-12-31
  • Java教程mybatis调用存储过程的实例代码

    mybatis调用存储过程的实例代码

    这篇文章主要介绍了mybatis调用存储过程的实例,非常不错,具有参考借鉴价值,需要的朋友可以参考下...

    动力节点11732021-01-25
  • Java教程二进制中1的个数

    二进制中1的个数

    这篇文章介绍了二进制中1的个数,有需要的朋友可以参考一下 ...

    java之家2662019-10-15
  • Java教程Spring Cloud Gateway 如何修改HTTP响应信息

    Spring Cloud Gateway 如何修改HTTP响应信息

    这篇文章主要介绍了Spring Cloud Gateway 修改HTTP响应信息的方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...

    帷幄庸者13712021-10-13
  • Java教程Java开发常见异常及解决办法详解

    Java开发常见异常及解决办法详解

    这篇文章主要介绍了java程序常见异常及处理汇总,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考...

    cutercorley12252021-12-18
  • Java教程浅谈sql_@SelectProvider及使用注意说明

    浅谈sql_@SelectProvider及使用注意说明

    这篇文章主要介绍了sql_@SelectProvider及使用注意说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...

    icecoola_6892021-11-04
  • Java教程mybatis批量新增、删除、查询和修改方式

    mybatis批量新增、删除、查询和修改方式

    这篇文章主要介绍了mybatis批量新增、删除、查询和修改方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...

    xuforeverlove7492022-01-24
  • Java教程浅谈java 中equals和==的区别

    浅谈java 中equals和==的区别

    这篇文章主要介绍了java 中equals和==的区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小...

    独特润许多人5982021-07-21