定时任务,即特定条件下触发,常用于业务周期性维护,如数据同步,业务检查,定期的业务处理...
定时任务要素:时机,执行。时机,即定时任务触发时机,执行,着重考虑的线程执行,串行或并行,线程维护。
环境配置:springboot
时机
@Scheduled 注解控制时机。控制参数
fixedRate:两次任务执行间隔,自带修正。
fixedRate:距离上次任务间隔
initialDelay:第一次执行间隔
cron:cron表达式
cron表达式(注意区分linux的cron表达式,linux精确到min,spring cron 精确到s),共七个占位符,第七个为可选项。
second, minute, hour, day, month, weekday,year
其中星期与月可用英文名称的前三个字母
通用符号,“,-*/”
- 逗号,列表值,
- 减号-,范围,如“10-13”等同于“10,11,1213"
- *,每一个时刻
- /,等步长序列,x/y,x是起点,y是步长
特殊字符
- ? 无意义的值。用于星期中。(星期与日不能同时实现,使用?进行兼容)
- nL 每月最后第n天或每个星期最后第n天(星期六)
- nW 离每月第n天最近的工作日(周一至周五,不能跨月),LW连用,本月最后一个工作日
- x#y 本月第y周的星期x-1(星期中7表示星期六)
- nC 本月(或星期)后n天
执行
每个定时任务都会开启一个线程进行,指定线程执行器ScheduledThreadPoolExecutor执行。为了更细粒度的控制线程,可以使用方法级别的异步,指定执行器ThreadPoolTaskExecutor。
相关代码
pom.xml
<?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>zl</groupId>
<artifactId>example</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>schedule</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.10.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application
package zl.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication(scanBasePackages="zl.example.config")
public class ScheduleApplication {
public static void main(String[] args) {
SpringApplication.run(ScheduleApplication.class, args);
}
}
定时任务执行器
package zl.example.config;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
@Configuration
@EnableScheduling
@ComponentScan(basePackages="zl.example.task")
public class ScheduleConfig implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(taskExecutor());
}
@Bean(destroyMethod="shutdown")
public Executor taskExecutor() {
ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(10);
executor.setMaximumPoolSize(100);
executor.setKeepAliveTime(300, TimeUnit.SECONDS);
executor.setRejectedExecutionHandler(new ScheduledThreadPoolExecutor.CallerRunsPolicy());
return executor;
//可以满足,至少是个10个任务在运行,30个任务在等待(多余的任务会创建新的线程),空闲线程300s不活动被销毁
// rejection-policy:当pool已经达到max size的时候,如何处理新任务
// CALLER_RUNS:不在新线程中执行任务,而是由调用者所在的线程来执行
/* Reject策略预定义有四种:
(1)ThreadPoolExecutor.AbortPolicy策略,是默认的策略,处理程序遭到拒绝将抛出运行时 RejectedExecutionException。
(2)ThreadPoolExecutor.CallerRunsPolicy策略 ,调用者的线程会执行该任务,如果执行器已关闭,则丢弃.
(3)ThreadPoolExecutor.DiscardPolicy策略,不能执行的任务将被丢弃.
(4)ThreadPoolExecutor.DiscardOldestPolicy策略,如果执行程序尚未关闭,则位于工作队列头部的任务将被删除,然后重试执行程序(如果再次失败,则重复此过程).*/
}
}
方法异步执行器
package zl.example.config;
import java.util.concurrent.Executor;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
@Configuration
@EnableAsync
@ComponentScan(basePackages="zl.example.task")
public class AsyncConfig implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(7);
executor.setMaxPoolSize(42);
executor.setQueueCapacity(11);
executor.setThreadNamePrefix("MyAsyncExecutor-");
executor.initialize();
return executor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return null;
}
}
异步方法
package zl.example.task;
import java.util.Calendar;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Component;
@Component
public class AsyncExample {
@Async
public Future<String> async(){
try {
TimeUnit.SECONDS.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("excute async " + Calendar.getInstance().get(Calendar.SECOND));
return new AsyncResult<>("async accomplished!");
}
}
定时任务
package zl.example.task;
import java.util.Calendar;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class ScheduleExample {
@Autowired
AsyncExample example;
@Scheduled(fixedRate=1000)
public void fixedRate(){//自带修正功能
System.out.println("excute fixedRate " + Calendar.getInstance().get(Calendar.SECOND));
}
@Scheduled(fixedRate=2000)
public void initialDelay(){
Future<String> async = example.async();
System.out.println("async finished ? "+ async.isDone());
System.out.println("excute fixedRate " + Calendar.getInstance().get(Calendar.SECOND));
}
@Scheduled(fixedDelay=1000)
public void fixedDelay() {
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("excute fixedDelay " + Calendar.getInstance().get(Calendar.SECOND));
}
@Scheduled(cron="0 0 0 * 2 ?")
public void cron() {
}
}