定时任务
1 Timer
这是java自带的java.util.Timer类,这个类允许你调度一个java.util.TimerTask任务。使用这种方式可以让你的程序按照某一个频度执行,但不能在指定时间运行。一般用的较少。
@Test
public void test1() throws IOException {
// 新建定时任务
TimerTask timerTask = new TimerTask() {
@Override
public void run() {
System.out.println("当前时间:"+ new Date());
}
};
Timer timer = new Timer();
// 安排任务执行
/*
任务
延迟时间
固定间隔
*/
timer.schedule(timerTask,10,3000);
System.in.read();
}
2 ScheduledExecutorService
jdk自带的一个类;是基于线程池设计的定时任务类,每个调度任务都会分配到线程池中的一个线程去执行,也就是说,任务是并发执行,互不影响。
@Test
public void test2() throws IOException {
ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
/*
任务
延迟时间
固定间隔
时间类型
*/
service.scheduleAtFixedRate(()-> System.out.println("当前时间;"+new Date()),1,5, TimeUnit.SECONDS);
System.in.read();
}
3 Spring Task
3.1 基本使用
@SpringBootApplication
// 开启定时任务支持
@EnableScheduling
public class TimerApplication {
public static void main(String[] args) {
SpringApplication.run(TimerApplication.class, args);
}
}
单线程
所有任务会在单个线程内执行,当有任务卡死时,其他任务也会无法执行
// 定时任务类
@Component
public class ScheduledService {
@Scheduled(cron = "0/5 * * * * *")
public void scheduled1(){
System.out.println("定时任务1"+new Date());
System.out.println(Thread.currentThread()); // Thread[scheduling-1,5,main]
}
@Scheduled(fixedRate = 5000)
public void scheduled2(){
System.out.println("定时任务2"+new Date());
System.out.println(Thread.currentThread()); // Thread[scheduling-1,5,main]
}
@Scheduled(fixedDelay = 5000)
public void scheduled3(){
System.out.println("定时任务3"+new Date());
System.out.println(Thread.currentThread()); // Thread[scheduling-1,5,main]
}
}
多线程
@Configuration
// 开启异步支持
@EnableAsync
public class Config {
@Bean
public Executor taskExecutor(){
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);
executor.setMaxPoolSize(200);
executor.setQueueCapacity(10);
executor.initialize();
return executor;
}
}
// 定时任务类
@Component
// 开启多线程
@Async
public class ScheduledService {
@Scheduled(cron = "0/5 * * * * *")
public void scheduled1(){
System.out.println("定时任务1"+new Date());
System.out.println(Thread.currentThread()); // Thread[scheduling-1,5,main]
}
@Scheduled(fixedRate = 5000)
public void scheduled2(){
System.out.println("定时任务2"+new Date());
System.out.println(Thread.currentThread()); // Thread[taskExecutor-2,5,main]
}
@Scheduled(fixedDelay = 5000)
public void scheduled3(){
System.out.println("定时任务3"+new Date());
System.out.println(Thread.currentThread()); // Thread[taskExecutor-3,5,main]
}
}
4 执行时间配置
- fixedRate:定义一个按一定频率执行的定时任务;
- fixedDelay:定义一个按一定频率执行的定时任务,该属性可以配合
initialDelay
, 定义该任务延迟执行时间。 - cron:通过表达式来配置任务执行时间。
4.1 cron表达式
一个cron表达式有至少6个(也可能7个)有空格分隔的时间元素:
- 秒(0~59)
- 分钟(0~59)
- 小时(0~23)
- 天(0~31)
- 月(0~11)
- 星期(1~7 1=SUN 或 SUN,MON,TUE,WED,THU,FRI,SAT)
- 年份(1970-2099)
字段 | 允许值 | 允许的特殊字符 |
---|---|---|
秒 | 0~59 | , - * / |
分 | 0~59 | , - * / |
小时 | 0~23 | , - * / |
日期 | 1-31 | , - * ? / L W C |
月份 | 112或者JANDEC | , - * / |
星期 | 17或者SUNSAT | , - * ? / L C # |
年(可选) | 留空,1970~2099 | , - * / |
含义:
,
:一个列表
-
:一个连续区间
8-18/4
:一个间隔时间
*
:所有可能的值
/
:指定数值的增量;0/15”表示从第0分钟开始,每15分钟;3/20”表示从第3分钟开始,每20分钟
?
:用于日期和星期,当一个指定值时,另一个使用,避免冲突
L
:表示倒数的某个时期
W
:代表平日,离该日最近的工作日触发
C
:代表Calendar,计划所关联的日期;5C在日期中相当于日历5日以后的第一天。
常见表达式
# 每隔5秒执行一次
0/5 * * * * *
# 每隔5分钟执行一次
* 0/5 * * * *
# 每天上午10点,下午2点,4点
0 0 10,14,16 * * ?
# 朝九晚五工作时间内每半小时
0 0/30 9-17 * * ?
# 每个星期三中午12点
0 0 12 ? * WED
# 每天中午12点
0 0 12 * * ?
# 在每天下午2点到下午2:59期间的每1分钟触发
0 * 14 * * ?
# 周一至周五的上午10:15触发
0 15 10 ? * MON-FRI
# 每月最后一日的上午10:15触发
0 15 10 L * ?
5 开/关定时任务
提供接口,可以通过访问接口的方式开启和关闭定时任务。
配置文件
corn1=0/5 * * * * *
开启支持
@SpringBootApplication
// 开启定时任务支持
@EnableScheduling
public class TimerApplication {
public static void main(String[] args) {
SpringApplication.run(TimerApplication.class, args);
}
}
控制层
@RestController
public class TestController {
@Autowired
private ThreadPoolTaskScheduler threadPoolTaskScheduler;
@Value("${corn1}")
private String corn1;
private ScheduledFuture<?> future1;
// 定义线程池
@Bean
public ThreadPoolTaskScheduler threadPoolTaskScheduler() {
return new ThreadPoolTaskScheduler();
}
// 开始定时任务
@GetMapping("/start")
public void start(){
// 防止多次请求
if (future1 != null) {
future1.cancel(true);
}
/*
定时任务
定时器
*/
future1 = threadPoolTaskScheduler.schedule(new Runnable() {
@Override
public void run() {
System.out.println("定时任务:"+new Date());
}
}, new Trigger() {
@Override
public Date nextExecutionTime(TriggerContext triggerContext) {
return new CronTrigger(corn1).nextExecutionTime(triggerContext);
}
});
System.out.println("开启定时任务");
}
// 关闭定时任务
@GetMapping("/stop")
public void stop(){
if (future1 != null) {
future1.cancel(true);
}
System.out.println("关闭定时任务");
}
}