使用@EnableScheduling开启功能
@Configuration
@EnableScheduling
public class ScheduleConfig {
}
编写任务
@Component
public class ScheduledTasks {
//表示上一次任务执行完成后多久再次执行,参数类型为long,单位ms;
@Scheduled(fixedDelay = 500)
public void fixedDelay(){
}
//表示按一定的频率执行任务,参数类型为long,单位ms;
@Scheduled(fixedRate = 500)
public void fixedRate(){
}
//cron表达式,指定任务在特定时间执行;
@Scheduled(cron="0 50 * * * ?")
public void cron(){
}
//第一次1秒后执行,当执行完后2秒再执行
@Scheduled(initialDelay = 1000, fixedDelay = 2000)
public void initialDelay() {
}
// 可以从配置文件中读取
@Scheduled(fixedDelayString = "${jobs.fixedDelay}")
public void fixedDelayString() {
}
/**
* cron:cron表达式,指定任务在特定时间执行;
* fixedDelay:表示上一次任务执行完成后多久再次执行,参数类型为long,单位ms;
* fixedDelayString:与fixedDelay含义一样,只是参数类型变为String;
* fixedRate:表示按一定的频率执行任务,参数类型为long,单位ms;
* fixedRateString: 与fixedRate的含义一样,只是将参数类型变为String;
* initialDelay:表示延迟多久再第一次执行任务,参数类型为long,单位ms;
* initialDelayString:与initialDelay的含义一样,只是将参数类型变为String;
*/
}
配置(可选)
@Configuration
public class ScheduleConfig implements SchedulingConfigurer, AsyncConfigurer{
//并行任务
public void configureTasks(ScheduledTaskRegistrar taskRegistrar){
TaskScheduler taskScheduler = taskScheduler();
taskRegistrar.setTaskScheduler(taskScheduler);
}
//并行任务使用策略:多线程处理(配置线程数等)
@Bean
public ThreadPoolTaskScheduler taskScheduler(){
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.setPoolSize(20);
scheduler.setThreadNamePrefix("task-"); //设置线程名开头
scheduler.setAwaitTerminationSeconds(60);
scheduler.setWaitForTasksToCompleteOnShutdown(true);
return scheduler;
}
//异步任务
public Executor getAsyncExecutor(){
Executor executor = taskScheduler();
return executor;
}
//异步任务 异常处理
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler(){
return new SimpleAsyncUncaughtExceptionHandler();
}
}
定时任务线程池中,不管配置多少个线程,每次到定时点,只有一个线程去执行任务。假如配置fixedDelay=500,表示上一次任务执行完后,延迟500毫秒执行下次任务。如果任务执行需要500毫秒,那么任务的执行周期是500+500=1000毫秒。就算线程池中有多个线程,也会等那个任务执行完再选取一个线程再次执行任务。
@Bean("aaa")
public TaskScheduler scheduler() {
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.setThreadNamePrefix("a");
scheduler.setPoolSize(4);
scheduler.initialize();
return scheduler;
}
@Scheduled(fixedDelay = 500)
public void scheduled(){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
LOGGER.info(Thread.currentThread().getName());
}
2018-10-11 10:18:44.705 com.demo.test.async.ScheduleService : a1
2018-10-11 10:18:45.710 com.demo.test.async.ScheduleService : a1
2018-10-11 10:18:46.714 com.demo.test.async.ScheduleService : a1
2018-10-11 10:18:47.715 com.demo.test.async.ScheduleService : a1
2018-10-11 10:18:48.716 com.demo.test.async.ScheduleService : a1
2018-10-11 10:18:49.719 com.demo.test.async.ScheduleService : a1
2018-10-11 10:18:50.720 com.demo.test.async.ScheduleService : a1
2018-10-11 10:18:51.722 com.demo.test.async.ScheduleService : a1
2018-10-11 10:18:52.723 com.demo.test.async.ScheduleService : a1
2018-10-11 10:18:53.724 com.demo.test.async.ScheduleService : a1
2018-10-11 10:18:54.725 com.demo.test.async.ScheduleService : a1
2018-10-11 10:18:55.726 com.demo.test.async.ScheduleService : a3
2018-10-11 10:18:56.727 com.demo.test.async.ScheduleService : a3
2018-10-11 10:18:57.729 com.demo.test.async.ScheduleService : a3
加入配置fixedRate = 500,表示每500毫秒执行一次任务。如果任务执行时间大于配置的值,则任务执行完毕立即执行下一个任务。
@Bean("aaa")
public TaskScheduler scheduler() {
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.setThreadNamePrefix("a");
scheduler.setPoolSize(4);
scheduler.initialize();
return scheduler;
}
@Scheduled(fixedRate = 500)
public void scheduled(){
LOGGER.info(Thread.currentThread().getName());
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
2018-10-11 11:01:21.218 com.demo.test.async.ScheduleService : a1
2018-10-11 11:01:23.219 com.demo.test.async.ScheduleService : a2
2018-10-11 11:01:25.220 com.demo.test.async.ScheduleService : a1
2018-10-11 11:01:27.221 com.demo.test.async.ScheduleService : a1
2018-10-11 11:01:29.221 com.demo.test.async.ScheduleService : a1
2018-10-11 11:01:31.222 com.demo.test.async.ScheduleService : a4
2018-10-11 11:01:33.223 com.demo.test.async.ScheduleService : a4
可以看到任务执行时间是2秒,大于配置500毫秒,所以任务执行完立即执行下一个任务。相当于执行周期变成了任务执行时间。
如果同时开启了@EnableAsync和使用了@Async,便变成了按配置时间(T),每T执行一次任务。如果任务执行时间大于T,则会选取线程池中其他的线程去执行任务,如果没有剩余线程,则会等待有线程空闲出来。
@EnableAsync
@Configuration
public class ScheduleConfig implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setTaskScheduler( scheduler());
}
@Bean("aaa")
public TaskScheduler scheduler() {
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.setThreadNamePrefix("a");
scheduler.setPoolSize(4);
scheduler.initialize();
return scheduler;
}
}
@Async("aaa")
@Scheduled(fixedRate = 500)
public void scheduled(){
LOGGER.info(Thread.currentThread().getName());
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
2018-10-11 11:12:35.326 com.demo.test.async.ScheduleService : a4
2018-10-11 11:12:35.830 com.demo.test.async.ScheduleService : a2
2018-10-11 11:12:36.338 com.demo.test.async.ScheduleService : a1
2018-10-11 11:12:36.830 com.demo.test.async.ScheduleService : a3
2018-10-11 11:12:37.326 com.demo.test.async.ScheduleService : a4
2018-10-11 11:12:37.836 com.demo.test.async.ScheduleService : a2
2018-10-11 11:12:38.338 com.demo.test.async.ScheduleService : a1
2018-10-11 11:12:38.830 com.demo.test.async.ScheduleService : a3
使用@EnableScheduling,同时不使用@EnableAsync和taskRegistrar也没有添加线程池,这时候执行定时任务,会使用默认的线程池(只有一个线程),多个任务同步执行
@Configuration
@EnableScheduling
public class ScheduleConfig implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
}
}
@Scheduled(fixedRate = 500)
public void scheduled(){
LOGGER.info(Thread.currentThread().getName() + " -- aaa");
}
@Scheduled(fixedDelay = 1000)
public void fileProcessScheduled(){
LOGGER.info(Thread.currentThread().getName() + " -- bbb");
}
2018-10-12 09:28:32.415 com.demo.test.async.ScheduleService : pool-1-thread-1 -- aaa
2018-10-12 09:28:32.429 com.demo.test.async.ScheduleService : pool-1-thread-1 -- bbb
2018-10-12 09:28:32.915 com.demo.test.async.ScheduleService : pool-1-thread-1 -- aaa
2018-10-12 09:28:33.415 com.demo.test.async.ScheduleService : pool-1-thread-1 -- aaa
2018-10-12 09:28:33.431 com.demo.test.async.ScheduleService : pool-1-thread-1 -- bbb
2018-10-12 09:28:33.915 com.demo.test.async.ScheduleService : pool-1-thread-1 -- aaa
使用@EnableScheduling,同时不使用@EnableAsync,然后在taskRegistrar添加指定线程池,这时候执行定时任务,会使用我们添加的线程池,多个任务同步执行
@Configuration
@EnableScheduling
public class ScheduleConfig implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setTaskScheduler(scheduler());
}
@Bean
public TaskScheduler scheduler() {
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.setThreadNamePrefix("a");
scheduler.setPoolSize(3);
scheduler.initialize();
return scheduler;
}
}
@Scheduled(fixedRate = 500)
public void scheduled(){
LOGGER.info(Thread.currentThread().getName() + " -- aaa");
}
@Scheduled(fixedDelay = 1000)
public void fileProcessScheduled(){
LOGGER.info(Thread.currentThread().getName() + " -- bbb");
}
2018-10-12 09:38:09.763 com.demo.test.async.ScheduleService : a2 -- aaa
2018-10-12 09:38:10.265 com.demo.test.async.ScheduleService : a2 -- aaa
2018-10-12 09:38:10.276 com.demo.test.async.ScheduleService : a1 -- bbb
2018-10-12 09:38:10.764 com.demo.test.async.ScheduleService : a3 -- aaa
2018-10-12 09:38:11.264 com.demo.test.async.ScheduleService : a3 -- aaa
2018-10-12 09:38:11.276 com.demo.test.async.ScheduleService : a2 -- bbb
2018-10-12 09:38:11.764 com.demo.test.async.ScheduleService : a1 -- aaa
使用@EnableScheduling和@EnableAsync,然后在任务上用@Async("xxx")指定线程池,taskRegistrar添加不添加线程池无影响,会使用指定的,不会用registrar里添加的,这时候执行定时任务,会使用各自指定的线程池,多个任务(非一个线程池)并行执行
@EnableAsync
@Configuration
@EnableScheduling
public class ScheduleConfig implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
}
@Bean("aaa")
public TaskScheduler a() {
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.setThreadNamePrefix("a");
scheduler.setPoolSize(3);
scheduler.initialize();
return scheduler;
}
@Bean("bbb")
public TaskScheduler fileProcessScheduler() {
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.setThreadNamePrefix("b");
scheduler.setPoolSize(2);
scheduler.initialize();
return scheduler;
}
}
@Async("aaa")
@Scheduled(fixedRate = 500)
public void scheduled(){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
LOGGER.info(Thread.currentThread().getName() + " -- aaa");
}
@Async("bbb")
@Scheduled(fixedDelay = 1000)
public void fileProcessScheduled(){
LOGGER.info(Thread.currentThread().getName() + " -- bbb");
}
2018-10-12 09:43:54.484 com.demo.test.async.ScheduleService : a2 -- aaa
2018-10-12 09:43:54.498 com.demo.test.async.ScheduleService : b2 -- bbb
2018-10-12 09:43:54.985 com.demo.test.async.ScheduleService : a3 -- aaa
2018-10-12 09:43:55.484 com.demo.test.async.ScheduleService : a1 -- aaa
2018-10-12 09:43:55.498 com.demo.test.async.ScheduleService : b1 -- bbb
2018-10-12 09:43:55.984 com.demo.test.async.ScheduleService : a2 -- aaa
2018-10-12 09:43:56.485 com.demo.test.async.ScheduleService : a3 -- aaa
2018-10-12 09:43:56.498 com.demo.test.async.ScheduleService : b2 -- bbb
2018-10-12 09:43:56.984 com.demo.test.async.ScheduleService : a1 -- aaa