当前位置:   article > 正文

SpringBoot多线程定时调度@Scheduled_springboot多线程执行调度

springboot多线程执行调度

 

@Scheduled在spring中默认是使用一个线程的线程池执行调度任务的。

下面是我的测试代码:

1、pom文件配置

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5. <modelVersion>4.0.0</modelVersion>
  6. <groupId>com.wsj.monitor</groupId>
  7. <artifactId>monitor</artifactId>
  8. <version>1.0-SNAPSHOT</version>
  9. <parent>
  10. <groupId>org.springframework.boot</groupId>
  11. <artifactId>spring-boot-starter-parent</artifactId>
  12. <version>2.0.7.RELEASE</version>
  13. </parent>
  14. <dependencies>
  15. <dependency>
  16. <groupId>org.springframework.boot</groupId>
  17. <artifactId>spring-boot-starter-quartz</artifactId>
  18. </dependency>
  19. <dependency>
  20. <groupId>org.springframework.boot</groupId>
  21. <artifactId>spring-boot-starter-test</artifactId>
  22. <scope>test</scope>
  23. </dependency>
  24. </dependencies>
  25. </project>

 启动类配置:

  1. import org.springframework.boot.SpringApplication;
  2. import org.springframework.boot.autoconfigure.SpringBootApplication;
  3. import org.springframework.scheduling.annotation.EnableScheduling;
  4. @SpringBootApplication
  5. @EnableScheduling
  6. public class MonitorApp {
  7. public static void main(String[] args) {
  8. SpringApplication.run(MonitorApp.class,args);
  9. }
  10. }

 测试job

  1. package com.tyyd.monitor.job;
  2. import org.springframework.scheduling.annotation.Scheduled;
  3. import org.springframework.stereotype.Component;
  4. import java.util.concurrent.TimeUnit;
  5. @Component
  6. public class TestJob {
  7. @Scheduled(cron = "0/10 * * * * ?")
  8. public void testJob1() throws InterruptedException {
  9. System.out.println("执行了TestJob1,执行的线程名称是:"+Thread.currentThread().getName());
  10. //休眠20秒
  11. TimeUnit.SECONDS.sleep(20);
  12. }
  13. @Scheduled(cron = "0/5 * * * * ?")
  14. public void testJob2(){
  15. System.out.println("执行了TestJob2,执行的线程名称是:"+Thread.currentThread().getName());
  16. }
  17. }

执行结果,看到使用的都是同线程池的线程。 

  1. 执行了TestJob2,执行的线程名称是:pool-1-thread-1
  2. 执行了TestJob2,执行的线程名称是:pool-1-thread-1
  3. 执行了TestJob1,执行的线程名称是:pool-1-thread-1
  4. 执行了TestJob2,执行的线程名称是:pool-1-thread-1
  5. 执行了TestJob2,执行的线程名称是:pool-1-thread-1
  6. 执行了TestJob1,执行的线程名称是:pool-1-thread-1

线程池使用配置:

  1. package com.wsj.monitor.config;
  2. import org.springframework.context.annotation.Configuration;
  3. import org.springframework.scheduling.annotation.SchedulingConfigurer;
  4. import org.springframework.scheduling.config.ScheduledTaskRegistrar;
  5. import java.util.concurrent.Executors;
  6. /***
  7. * @Scheduled 注解默认使用的是单线程,1个任务卡死。会产生连锁反应。
  8. * 配置任务线程池可以让同步任务并行执行调度
  9. * @Scheduled(cron="0 1***?")
  10. */
  11. @Configuration
  12. public class ScheduleConfig implements SchedulingConfigurer {
  13. @Override
  14. public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
  15. //设定一个启动10个线程的定时调度线程池
  16. taskRegistrar.setScheduler(Executors.newScheduledThreadPool(10));
  17. }
  18. }

配置后执行结果

  1. 执行了TestJob2,执行的线程名称是:pool-1-thread-1
  2. 执行了TestJob2,执行的线程名称是:pool-1-thread-2
  3. 执行了TestJob1,执行的线程名称是:pool-1-thread-1
  4. 执行了TestJob2,执行的线程名称是:pool-1-thread-3
  5. 执行了TestJob2,执行的线程名称是:pool-1-thread-2
  6. 执行了TestJob2,执行的线程名称是:pool-1-thread-4
  7. 执行了TestJob2,执行的线程名称是:pool-1-thread-3
  8. 执行了TestJob2,执行的线程名称是:pool-1-thread-5
  9. 执行了TestJob2,执行的线程名称是:pool-1-thread-6
  10. 执行了TestJob1,执行的线程名称是:pool-1-thread-2
  11. 执行了TestJob2,执行的线程名称是:pool-1-thread-4
  12. 执行了TestJob2,执行的线程名称是:pool-1-thread-4
  13. 执行了TestJob2,执行的线程名称是:pool-1-thread-3
  14. 执行了TestJob2,执行的线程名称是:pool-1-thread-3
  15. 执行了TestJob2,执行的线程名称是:pool-1-thread-3

注意,spring 的quartz是可以使用异步的。再启动类上开启异步支持@EnableAsync 并在要异步的任务上加个@Async。

如果所有的任务都使用异步,线程池执行的话,可以不配置同步任务线程池。但是使用异步需要注意的是异步线程池的大小配置。异步的线程池默认是无上限的开启线程数的。

  1. @Component
  2. public class TestJob {
  3. @Async
  4. @Scheduled(cron = "0/3 * * * * ?")
  5. public void testJob1() throws InterruptedException {
  6. System.out.println("执行了TestJob1,执行的线程名称是:"+Thread.currentThread().getName());
  7. TimeUnit.SECONDS.sleep(20);
  8. }
  9. @Scheduled(cron = "0/5 * * * * ?")
  10. public void testJob2(){
  11. System.out.println("执行了TestJob2,执行的线程名称是:"+Thread.currentThread().getName());
  12. }
  13. }

执行结果: 

  1. 执行了TestJob1,执行的线程名称是:SimpleAsyncTaskExecutor-1
  2. 执行了TestJob1,执行的线程名称是:SimpleAsyncTaskExecutor-2
  3. 执行了TestJob2,执行的线程名称是:pool-1-thread-1
  4. 执行了TestJob1,执行的线程名称是:SimpleAsyncTaskExecutor-3
  5. 执行了TestJob2,执行的线程名称是:pool-1-thread-2
  6. 执行了TestJob1,执行的线程名称是:SimpleAsyncTaskExecutor-4
  7. 执行了TestJob1,执行的线程名称是:SimpleAsyncTaskExecutor-5
  8. 执行了TestJob2,执行的线程名称是:pool-1-thread-3
  9. 执行了TestJob1,执行的线程名称是:SimpleAsyncTaskExecutor-6
  10. 执行了TestJob1,执行的线程名称是:SimpleAsyncTaskExecutor-7
  11. 执行了TestJob2,执行的线程名称是:pool-1-thread-2
  12. 执行了TestJob1,执行的线程名称是:SimpleAsyncTaskExecutor-8
  13. 执行了TestJob2,执行的线程名称是:pool-1-thread-8
  14. 执行了TestJob1,执行的线程名称是:SimpleAsyncTaskExecutor-9
  15. 执行了TestJob1,执行的线程名称是:SimpleAsyncTaskExecutor-10

 因为异步线程池没做控制默认无上限肯定不行的。修改配置如下:

  1. package com.wsj.monitor.config;
  2. import org.springframework.context.annotation.Bean;
  3. import org.springframework.context.annotation.Configuration;
  4. import org.springframework.core.task.SimpleAsyncTaskExecutor;
  5. import org.springframework.scheduling.annotation.EnableAsync;
  6. import org.springframework.scheduling.annotation.SchedulingConfigurer;
  7. import org.springframework.scheduling.config.ScheduledTaskRegistrar;
  8. import java.util.concurrent.Executors;
  9. /***
  10. * @Scheduled 注解默认使用的是单线程,1个任务卡死。会产生连锁反应。
  11. * 配置任务线程池可以并行执行调度
  12. * @Async
  13. * @Scheduled(cron="0 1***?")
  14. * 可以在scheduled上加上异步注解 ,每个任务都是一个新的线程
  15. * 如果是异步,每卡住一个任务都会占用一个线程资源,直到线程池线程资源全部占用定时调度挂掉
  16. */
  17. @Configuration
  18. @EnableAsync
  19. public class ScheduleConfig implements SchedulingConfigurer {
  20. @Override
  21. public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
  22. //设定一个长度10的定时任务线程池
  23. taskRegistrar.setScheduler(Executors.newScheduledThreadPool(10));
  24. }
  25. /**
  26. * 异步线程池设置
  27. * @return
  28. */
  29. @Bean
  30. SimpleAsyncTaskExecutor simpleAsyncTaskExecutor(){
  31. SimpleAsyncTaskExecutor simpleAsyncTaskExecutor = new SimpleAsyncTaskExecutor();
  32. simpleAsyncTaskExecutor.setConcurrencyLimit(2);//设置最大并行数
  33. simpleAsyncTaskExecutor.setDaemon(true); //设置为守护线程
  34. return simpleAsyncTaskExecutor;
  35. }
  36. }

修改配置后,看到执行结果最大同时异步为2个结果如下: 

  1. 执行了TestJob1,执行的线程名称是:SimpleAsyncTaskExecutor-1
  2. 执行了TestJob2,执行的线程名称是:pool-1-thread-2
  3. 执行了TestJob1,执行的线程名称是:SimpleAsyncTaskExecutor-2
  4. 执行了TestJob2,执行的线程名称是:pool-1-thread-4
  5. 执行了TestJob2,执行的线程名称是:pool-1-thread-1
  6. 执行了TestJob2,执行的线程名称是:pool-1-thread-5
  7. 执行了TestJob1,执行的线程名称是:SimpleAsyncTaskExecutor-3
  8. 执行了TestJob2,执行的线程名称是:pool-1-thread-6
  9. 执行了TestJob1,执行的线程名称是:SimpleAsyncTaskExecutor-4
  10. 执行了TestJob2,执行的线程名称是:pool-1-thread-1
  11. 执行了TestJob2,执行的线程名称是:pool-1-thread-8
  12. 执行了TestJob2,执行的线程名称是:pool-1-thread-8
  13. 执行了TestJob1,执行的线程名称是:SimpleAsyncTaskExecutor-5
  14. 执行了TestJob2,执行的线程名称是:pool-1-thread-8
  15. 执行了TestJob1,执行的线程名称是:SimpleAsyncTaskExecutor-6
  16. 执行了TestJob2,执行的线程名称是:pool-1-thread-8
  17. 执行了TestJob2,执行的线程名称是:pool-1-thread-5
  18. 执行了TestJob2,执行的线程名称是:pool-1-thread-5

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/52501
推荐阅读
相关标签