传统定时任务实现的几种方式:
Timer:这是java自带的java.util.Timer类,这个类允许你调度一个java.util.TimerTask任务。使用这种方式可以让你的程序按照某一个频度执行,但不能在指定时间运行。一般用的较少。
ScheduledExecutorService:也jdk自带的一个类;是基于线程池设计的定时任务类,每个调度任务都会分配到线程池中的一个线程去执行,也就是说,任务是并发执行,互不影响。
Spring Task:Spring3.0以后自带的task,可以将它看成一个轻量级的Quartz,而且使用起来比Quartz简单许多。
Quartz:这是一个功能比较强大的的调度器,可以让你的程序在指定时间执行,也可以按照某一个频度执行,配置起来稍显复杂。
在SpringBoot项目中,我们可以很简单的使用注解(@Scheduled)来实现定时任务
首先了解一下@Scheduled这个注解
@Scheduled接受两种定时的设置:
一种是cornexpression。
一种是Rate/Delay表达式(毫秒值):
@Scheduled(fixedRate = 6000):上一次开始执行时间点后每隔6秒执行一次。
@Scheduled(fixedDelay = 6000):上一次执行完毕时间点之后6秒再执行。
@Scheduled(initialDelay=1000, fixedRate=6000):第一次延迟1秒后执行,之后按fixedRate的规则每6秒执行一次。
注:
*表示所有值,在分钟里表示每一分钟触发。在小时,日期,月份等里面表示每一小时,每一日,每一月。
?表示不指定值。表示不关心当前位置设置的值。 比如不关心是周几,则周的位置填写?。  主要是由于日期跟周是有重复的所以两者必须有一者设置为?
- 表示区间。小时设置为10-12表示10,11,12点均会触发。
,表示多个值。 小时设置成10,12表示10点和12点会触发。
/ 表示递增触发。 5/15表示从第5秒开始,每隔15秒触发。
L 表示最后的意思。 日上表示最后一天。星期上表示星期六或7。 L前加数据,表示该数据的最后一个。
星期上设置6L表示最后一个星期五。 6表示星期五
W表示离指定日期最近的工作日触发。15W离该月15号最近的工作日触发。
#表示每月的第几个周几。 6#3表示该月的第三个周五。
示例:
"0 0 12 * * ?" 每天中午12点触发
"0 15 10 ? * *" 每天上午10:15触发
"0 15 10 * * ?" 每天上午10:15触发
"0 15 10 * * ? *" 每天上午10:15触发
"0 15 10 * * ? 2005" 2005年的每天上午10:15触发
"0 * 14 * * ?" 在每天下午2点到下午2:59期间的每1分钟触发
"0 0/5 14 * * ?" 在每天下午2点到下午2:55期间的每5分钟触发
"0 0/5 14,18 * * ?" 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发
"0 0-5 14 * * ?" 在每天下午2点到下午2:05期间的每1分钟触发
"0 10,44 14 ? 3 WED" 每年三月的星期三的下午2:10和2:44触发
"0 15 10 ? * MON-FRI" 周一至周五的上午10:15触发
"0 15 10 15 * ?" 每月15日上午10:15触发
"0 15 10 L * ?" 每月最后一日的上午10:15触发
"0 15 10 ? * 6L" 每月的最后一个星期五上午10:15触发
"0 15 10 ? * 6L 2002-2005" 2002年至2005年的每月的最后一个星期五上午10:15触发
"0 15 10 ? * 6#3" 每月的第三个星期五上午10:15触发
每天早上6点 0 6 * * * 每两个小时 0 */2 * * *
晚上11点到早上8点之间每两个小时,早上八点 0 23-7/2,8 * * *
每个月的4号和每个礼拜的礼拜一到礼拜三的早上11点 0 11 4 * 1-3
1月1日早上4点 0 4 1 1 *
在线Cron表达式生成器: cron.qqe2.com/
在主类上使用@EnableScheduling注解开启对定时任务的支持
@Component
public class ScheduledTest {
private static Logger logger = LoggerFactory.getLogger(ScheduledTest.class);
@Scheduled(cron = "0/5 * * * * *")
public void scheduled(){
logger.info("=====>>>>>cron执行-{}",DateUtils.getCurrentDateMillTime());
}
@Scheduled(fixedRate = 5000)
public void scheduled1() {
logger.info("=====>>>>>fixedRate执行-{}", DateUtils.getCurrentDateMillTime());
}
@Scheduled(fixedDelay = 5000)
public void scheduled2() {
logger.info("=====>>>>>fixedDelay执行-{}",DateUtils.getCurrentDateMillTime());
}
}
重启项目发现后台已经有任务在定时执行,时间间隔5秒
三个定时任务都已经执行,并且使同一个线程中串行执行,如果只有一个定时任务,这样做肯定没问题,当定时任务增多,如果一个任务卡死,会导致其他任务也无法执行,这时候就要使用多线程执行
创建AsyncConfig类:
@Configuration
@EnableAsync //开启异步事件的支持
public class AsyncConfig {
@Value("${corePoolSize}")
private int corePoolSize;
@Value("${maxPoolSize}")
private int maxPoolSize;
@Value("${queueCapacity}")
private int queueCapacity;
@Bean
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(maxPoolSize);
executor.setQueueCapacity(queueCapacity);
executor.initialize();
return executor;
}
}
相应配置文件:
#定时任务配置
corePoolSize: 10
maxPoolSize: 200
queueCapacity: 10
最后,在定时任务的类或者方法上添加@Async 。最后重启项目,每一个任务都是在不同的线程中,相互之间不影响