spring自带的定时任务功能@EnableScheduling

1 demo

package com.test.domi.config;

import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.text.SimpleDateFormat;
import java.util.Date;

@Component
@Configurable
@EnableScheduling
public class ScheduledTasks {
//每30秒执行一次
@Scheduled(fixedRate = 1000 * 30)
public void reportCurrentTime(){
System.out.println ("Scheduling Tasks Examples: The time is now " + dateFormat ().format (new Date ()));
}

//在固定时间执行
@Scheduled(cron = "0 */1 *  * * * ")
public void reportCurrentByCron(){
    System.out.println ("Scheduling Tasks Examples By Cron: The time is now " + dateFormat ().format (new Date()));
}

private SimpleDateFormat dateFormat(){
    return new SimpleDateFormat ("HH:mm:ss");
}

}
Scheduling Tasks Examples: The time is now 11:55:54
Scheduling Tasks Examples By Cron: The time is now 11:56:00
Scheduling Tasks Examples: The time is now 11:56:24
Scheduling Tasks Examples: The time is now 11:56:54
Scheduling Tasks Examples By Cron: The time is now 11:57:00

2 详解

http://tramp.cincout.cn/2017/08/18/spring-task-2017-08-18-spring-boot-enablescheduling-analysis/

cron表达式:https://www.zhyd.me/article/43

1.cron是设置定时执行的表达式,如 0 0/5 * * * ?每隔五分钟执行一次

2.zone表示执行时间的时区

3.fixedDelay 和fixedDelayString 一个固定延迟时间执行,上个任务完成后,延迟多久执行

4.fixedRate 和fixedRateString一个固定频率执行,上个任务开始后多长时间后开始执行

5.initialDelay 和initialDelayString表示一个初始延迟时间,第一次被调用前延迟的时间

3 总结常见问题

a: 单线程任务丢失,转为异步线程池

默认的 ConcurrentTaskScheduler 计划执行器采用Executors.newSingleThreadScheduledExecutor() 实现单线程的执行器。因此,对同一个调度任务的执行总是同一个线程。如果任务的执行时间超过该任务的下一次执行时间,则会出现任务丢失,跳过该段时间的任务。上述问题有以下解决办法:

采用异步的方式执行调度任务,配置 Spring 的 @EnableAsync,在执行定时任务的方法上标注 @Async配置任务执行池,线程池大小 n 的数量为 单个任务执行所需时间 / 任务执行的间隔时间。如下:

//每30秒执行一次
@Async("taskExecutor")
@Scheduled(fixedRate = 1000 * 3)
public void reportCurrentTime(){
System.out.println ("线程" + Thread.currentThread().getName() + "开始执行定时任务===&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&7&&&====》"
+ new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
long start = System.currentTimeMillis();
Future isOk1;
Future isOk2;
。 。。。。。。。。。省略。。。。。。。

b: 关于分布式情况下,重复执行的问题(两种方案)

1:可以使用redis的分布式锁保证spring schedule集群只执行一次。 redis分布式锁是通过setnx命令实现的。该命令的作用是,当往redis中存入一个值时,会先判断该值对应的key是否存在,如果存在则返回0,如果不存在,则将该值存入redis并返回1。(但是在分布式跨时区部署的时候,依然无法避免重复执行)

@Component
@Configuration
@EnableScheduling
public class AutoConvertTask {
private static final Logger logger = LoggerFactory.getLogger(AutoConvertTask.class);

@Autowired
private RedisTemplate redisTemplate;

private static final String LOCK = "task-job-lock";

private static final String KEY = "tasklock";

@Scheduled(cron = "0 0 0 * * ? ")
public void autoConvertJob() {
    boolean lock = false;
    try {
        lock = redisTemplate.opsForValue().setIfAbsent(KEY, LOCK);
        logger.info("是否获取到锁:" + lock);
        if (lock) {
            List<GameHistory> historyList = historyService.findTenDaysAgoUntreated();
            for (GameHistory history : historyList) {
                update(history);
            }
        } else {
            logger.info("没有获取到锁,不执行任务!");
            return;
        }
    } finally {
        if (lock) {
            redisTemplate.delete(KEY);
            logger.info("任务结束,释放锁!");
        } else {
            logger.info("没有获取到锁,无需释放锁!");
        }
    }

}

}

2:可以通过使用shedlock将spring schedule上锁。详细见:https://segmentfault.com/a/1190000011975027

c: 服务器宕机之后,丢失的任务如何补偿? 

可以将每次的任务执行时间缓在redis里,下次执行任务的时候都取出该时间,判断是否为上一个周期,如果不是,可以计算出中间丢失的周期数,然后做响应的补偿操作。如果怕redis宕机,可以将“执行时间”持久化到表中。

原文地址:https://www.cnblogs.com/ncwoniu/p/11993913.html

时间: 2024-08-11 21:23:17

spring自带的定时任务功能@EnableScheduling的相关文章

spring自带的定时任务功能,基于注解和xml配置

1.spring的配置文件 [html] view plain copy <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:task="http:

SpringMVC整合Quartz实现定时任务和Spring自带Task定时任务

一.Quartz定时任务1.引入quartz 导入quartz.jar包,或者pom.xml 配置对应的依赖: <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>1.8.6</version> </dependency> 2. Web.xml配置在Web项目web.xml中配

【Spring】JavaMailSender Spring自带的邮件推送功能实现

备注:JavaMailSender在spring-context-support.jar中 1.配置spring-mail.xml <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-ins

spring boot 学习(八)定时任务 @Scheduled

SpringBoot 定时任务 @Scheduled 前言 有时候,我们有这样的需求,需要在每天的某个固定时间或者每隔一段时间让应用去执行某一个任务.一般情况下,可以使用多线程来实现这个功能:在 Spring 框架下可以搭配 Quartz 来实现,附上笔记 Spring Quartz 实现多任务定时调用.在 SpringBoot 框架下,我们可以用 Spring scheduling 来实现定时任务功能. 首先,我们先创建一个 Spring Boot 项目.创建方法: * (自动完成初始化)ht

Spring Boot 中实现定时任务的两种方式

在 Spring + SpringMVC 环境中,一般来说,要实现定时任务,我们有两中方案,一种是使用 Spring 自带的定时任务处理器 @Scheduled 注解,另一种就是使用第三方框架 Quartz ,Spring Boot 源自 Spring+SpringMVC ,因此天然具备这两个 Spring 中的定时任务实现策略,当然也支持 Quartz,本文我们就来看下 Spring Boot 中两种定时任务的实现方式. @Scheduled 使用 @Scheduled 非常容易,直接创建一个

使用spring自带定时器: @Scheduled

项目开发中需要执行一些定时任务,比如需要在每天凌晨时候,分析一次前一天的日志信息之类的.平时使用Quartz比较多,但配置相对麻烦一点.今天就来说说Spring自带的定时任务. Spring自带实现定时任务有两种方式,一种是通过注解的方式实现,一种是通过在配置文件中配置后实现. 一.通过spring的注解( @Scheduled)实现定时任务. 首先当然是Springde 配置: 第一步:添加这三段: xmlns:task="http://www.springframework.org/sche

Spring自带定时器实现定时任务

在Spring框架中实现定时任务的办法至少有2种(不包括Java原生的Timer及Executor实现方式),一种是集成第三方定时任务框架,如无处不在的Quartz:另一种便是Spring自带的定时器(仅针对3.0之后的版本).本文将围绕Spring自带定时器,模拟实现一个最简单的定时任务,看看使用起来到底有多简单. 第二步,启动Schedule配置,XML方式的配置请自行搜索,本文仅针对注解方式的实现提供说明. @EnableScheduling @EnableScheduling注解,用来引

Spring Boot(九):定时任务

Spring Boot(九):定时任务 一.pom包配置 pom包里面只需要引入springboot starter包即可 <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> &

Common LISP自带单步跟踪功能

Common LISP自带单步跟踪功能,执行 (step 要跟踪的命令)即可.以sdraw为例,跟踪其执行. [1]启动单步跟踪 SDRAW[60]> (step (sdraw '(a (b c d) c))) step 1 --> (SDRAW '(A (B C D) C))     显示下一个要执行的语句 Step 1 SDRAW[61]>                         等待用户输入调试指令 [2]输入help查看帮助,帮助的内容很多,前面一大段和Debug是一样的