学习springBoot(12)定时任务

299 阅读5分钟

传统定时任务实现的几种方式:

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 。最后重启项目,每一个任务都是在不同的线程中,相互之间不影响