@Scheduled在spring中默認是使用一個線程的線程池執行調度任務的。
下面是我的測試代碼:
1、pom文件配置
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.wsj.monitor</groupId>
<artifactId>monitor</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.7.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
啓動類配置:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling
public class MonitorApp {
public static void main(String[] args) {
SpringApplication.run(MonitorApp.class,args);
}
}
測試job
package com.tyyd.monitor.job;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
@Component
public class TestJob {
@Scheduled(cron = "0/10 * * * * ?")
public void testJob1() throws InterruptedException {
System.out.println("執行了TestJob1,執行的線程名稱是:"+Thread.currentThread().getName());
//休眠20秒
TimeUnit.SECONDS.sleep(20);
}
@Scheduled(cron = "0/5 * * * * ?")
public void testJob2(){
System.out.println("執行了TestJob2,執行的線程名稱是:"+Thread.currentThread().getName());
}
}
執行結果,看到使用的都是同線程池的線程。
執行了TestJob2,執行的線程名稱是:pool-1-thread-1
執行了TestJob2,執行的線程名稱是:pool-1-thread-1
執行了TestJob1,執行的線程名稱是:pool-1-thread-1
執行了TestJob2,執行的線程名稱是:pool-1-thread-1
執行了TestJob2,執行的線程名稱是:pool-1-thread-1
執行了TestJob1,執行的線程名稱是:pool-1-thread-1
線程池使用配置:
package com.wsj.monitor.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import java.util.concurrent.Executors;
/***
* @Scheduled 註解默認使用的是單線程,1個任務卡死。會產生連鎖反應。
* 配置任務線程池可以讓同步任務並行執行調度
* @Scheduled(cron="0 1***?")
*/
@Configuration
public class ScheduleConfig implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
//設定一個啓動10個線程的定時調度線程池
taskRegistrar.setScheduler(Executors.newScheduledThreadPool(10));
}
}
配置後執行結果
執行了TestJob2,執行的線程名稱是:pool-1-thread-1
執行了TestJob2,執行的線程名稱是:pool-1-thread-2
執行了TestJob1,執行的線程名稱是:pool-1-thread-1
執行了TestJob2,執行的線程名稱是:pool-1-thread-3
執行了TestJob2,執行的線程名稱是:pool-1-thread-2
執行了TestJob2,執行的線程名稱是:pool-1-thread-4
執行了TestJob2,執行的線程名稱是:pool-1-thread-3
執行了TestJob2,執行的線程名稱是:pool-1-thread-5
執行了TestJob2,執行的線程名稱是:pool-1-thread-6
執行了TestJob1,執行的線程名稱是:pool-1-thread-2
執行了TestJob2,執行的線程名稱是:pool-1-thread-4
執行了TestJob2,執行的線程名稱是:pool-1-thread-4
執行了TestJob2,執行的線程名稱是:pool-1-thread-3
執行了TestJob2,執行的線程名稱是:pool-1-thread-3
執行了TestJob2,執行的線程名稱是:pool-1-thread-3
注意,spring 的quartz是可以使用異步的。再啓動類上開啓異步支持@EnableAsync 並在要異步的任務上加個@Async。
如果所有的任務都使用異步,線程池執行的話,可以不配置同步任務線程池。但是使用異步需要注意的是異步線程池的大小配置。異步的線程池默認是無上限的開啓線程數的。
@Component
public class TestJob {
@Async
@Scheduled(cron = "0/3 * * * * ?")
public void testJob1() throws InterruptedException {
System.out.println("執行了TestJob1,執行的線程名稱是:"+Thread.currentThread().getName());
TimeUnit.SECONDS.sleep(20);
}
@Scheduled(cron = "0/5 * * * * ?")
public void testJob2(){
System.out.println("執行了TestJob2,執行的線程名稱是:"+Thread.currentThread().getName());
}
}
執行結果:
執行了TestJob1,執行的線程名稱是:SimpleAsyncTaskExecutor-1
執行了TestJob1,執行的線程名稱是:SimpleAsyncTaskExecutor-2
執行了TestJob2,執行的線程名稱是:pool-1-thread-1
執行了TestJob1,執行的線程名稱是:SimpleAsyncTaskExecutor-3
執行了TestJob2,執行的線程名稱是:pool-1-thread-2
執行了TestJob1,執行的線程名稱是:SimpleAsyncTaskExecutor-4
執行了TestJob1,執行的線程名稱是:SimpleAsyncTaskExecutor-5
執行了TestJob2,執行的線程名稱是:pool-1-thread-3
執行了TestJob1,執行的線程名稱是:SimpleAsyncTaskExecutor-6
執行了TestJob1,執行的線程名稱是:SimpleAsyncTaskExecutor-7
執行了TestJob2,執行的線程名稱是:pool-1-thread-2
執行了TestJob1,執行的線程名稱是:SimpleAsyncTaskExecutor-8
執行了TestJob2,執行的線程名稱是:pool-1-thread-8
執行了TestJob1,執行的線程名稱是:SimpleAsyncTaskExecutor-9
執行了TestJob1,執行的線程名稱是:SimpleAsyncTaskExecutor-10
因爲異步線程池沒做控制默認無上限肯定不行的。修改配置如下:
package com.wsj.monitor.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import java.util.concurrent.Executors;
/***
* @Scheduled 註解默認使用的是單線程,1個任務卡死。會產生連鎖反應。
* 配置任務線程池可以並行執行調度
* @Async
* @Scheduled(cron="0 1***?")
* 可以在scheduled上加上異步註解 ,每個任務都是一個新的線程
* 如果是異步,每卡住一個任務都會佔用一個線程資源,直到線程池線程資源全部佔用定時調度掛掉
*/
@Configuration
@EnableAsync
public class ScheduleConfig implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
//設定一個長度10的定時任務線程池
taskRegistrar.setScheduler(Executors.newScheduledThreadPool(10));
}
/**
* 異步線程池設置
* @return
*/
@Bean
SimpleAsyncTaskExecutor simpleAsyncTaskExecutor(){
SimpleAsyncTaskExecutor simpleAsyncTaskExecutor = new SimpleAsyncTaskExecutor();
simpleAsyncTaskExecutor.setConcurrencyLimit(2);//設置最大並行數
simpleAsyncTaskExecutor.setDaemon(true); //設置爲守護線程
return simpleAsyncTaskExecutor;
}
}
修改配置後,看到執行結果最大同時異步爲2個結果如下:
執行了TestJob1,執行的線程名稱是:SimpleAsyncTaskExecutor-1
執行了TestJob2,執行的線程名稱是:pool-1-thread-2
執行了TestJob1,執行的線程名稱是:SimpleAsyncTaskExecutor-2
執行了TestJob2,執行的線程名稱是:pool-1-thread-4
執行了TestJob2,執行的線程名稱是:pool-1-thread-1
執行了TestJob2,執行的線程名稱是:pool-1-thread-5
執行了TestJob1,執行的線程名稱是:SimpleAsyncTaskExecutor-3
執行了TestJob2,執行的線程名稱是:pool-1-thread-6
執行了TestJob1,執行的線程名稱是:SimpleAsyncTaskExecutor-4
執行了TestJob2,執行的線程名稱是:pool-1-thread-1
執行了TestJob2,執行的線程名稱是:pool-1-thread-8
執行了TestJob2,執行的線程名稱是:pool-1-thread-8
執行了TestJob1,執行的線程名稱是:SimpleAsyncTaskExecutor-5
執行了TestJob2,執行的線程名稱是:pool-1-thread-8
執行了TestJob1,執行的線程名稱是:SimpleAsyncTaskExecutor-6
執行了TestJob2,執行的線程名稱是:pool-1-thread-8
執行了TestJob2,執行的線程名稱是:pool-1-thread-5
執行了TestJob2,執行的線程名稱是:pool-1-thread-5