定时任务最简单的3种实现方法(超好用)下

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
简介: 定时任务最简单的3种实现方法(超好用)

TOP 3:Spring Task


如果使用的是 Spring 或 Spring Boot 框架,可以直接使用 Spring Framework 自带的定时任务,使用上面两种定时任务的实现方式,很难实现设定了具体时间的定时任务,比如当我们需要每周五来执行某项任务时,但如果使用 Spring Task 就可轻松的实现此需求。


以 Spring Boot 为例,实现定时任务只需两步:


  1. 开启定时任务;
  2. 添加定时任务。


具体实现步骤如下。


① 开启定时任务


开启定时任务只需要在 Spring Boot 的启动类上声明 @EnableScheduling 即可,实现代码如下:


@SpringBootApplication
@EnableScheduling // 开启定时任务
public class DemoApplication {
    // do someing
}


② 添加定时任务


定时任务的添加只需要使用 @Scheduled 注解标注即可,如果有多个定时任务可以创建多个 @Scheduled 注解标注的方法,示例代码如下:


import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component // 把此类托管给 Spring,不能省略
public class TaskUtils {
    // 添加定时任务
    @Scheduled(cron = "59 59 23 0 0 5") // cron 表达式,每周五 23:59:59 执行
    public void doTask(){
        System.out.println("我是定时任务~");
    }
}


注意:定时任务是自动触发的无需手动干预,也就是说 Spring Boot 启动后会自动加载并执行定时任务。


Cron 表达式


Spring Task 的实现需要使用 cron 表达式来声明执行的频率和规则,cron 表达式是由 6 位或者 7 位组成的(最后一位可以省略),每位之间以空格分隔,每位从左到右代表的含义如下:


image.png


其中 * 和 ? 号都表示匹配所有的时间。


image.png


cron 表达式在线生成地址:https://cron.qqe2.com/


知识扩展:分布式定时任务


上面的方法都是关于单机定时任务的实现,如果是分布式环境可以使用 Redis 来实现定时任务。


使用 Redis 实现延迟任务的方法大体可分为两类:通过 ZSet 的方式和键空间通知的方式


① ZSet 实现方式


通过 ZSet 实现定时任务的思路是,将定时任务存放到 ZSet 集合中,并且将过期时间存储到 ZSet 的 Score 字段中,然后通过一个无线循环来判断当前时间内是否有需要执行的定时任务,如果有则进行执行,具体实现代码如下:


import redis.clients.jedis.Jedis;
import utils.JedisUtils;
import java.time.Instant;
import java.util.Set;
public class DelayQueueExample {
    // zset key
    private static final String _KEY = "myTaskQueue";
    public static void main(String[] args) throws InterruptedException {
        Jedis jedis = JedisUtils.getJedis();
        // 30s 后执行
        long delayTime = Instant.now().plusSeconds(30).getEpochSecond();
        jedis.zadd(_KEY, delayTime, "order_1");
        // 继续添加测试数据
        jedis.zadd(_KEY, Instant.now().plusSeconds(2).getEpochSecond(), "order_2");
        jedis.zadd(_KEY, Instant.now().plusSeconds(2).getEpochSecond(), "order_3");
        jedis.zadd(_KEY, Instant.now().plusSeconds(7).getEpochSecond(), "order_4");
        jedis.zadd(_KEY, Instant.now().plusSeconds(10).getEpochSecond(), "order_5");
        // 开启定时任务队列
        doDelayQueue(jedis);
    }
    /**
     * 定时任务队列消费
     * @param jedis Redis 客户端
     */
    public static void doDelayQueue(Jedis jedis) throws InterruptedException {
        while (true) {
            // 当前时间
            Instant nowInstant = Instant.now();
            long lastSecond = nowInstant.plusSeconds(-1).getEpochSecond(); // 上一秒时间
            long nowSecond = nowInstant.getEpochSecond();
            // 查询当前时间的所有任务
            Set<String> data = jedis.zrangeByScore(_KEY, lastSecond, nowSecond);
            for (String item : data) {
                // 消费任务
                System.out.println("消费:" + item);
            }
            // 删除已经执行的任务
            jedis.zremrangeByScore(_KEY, lastSecond, nowSecond);
            Thread.sleep(1000); // 每秒查询一次
        }
    }
}


② 键空间通知


我们可以通过 Redis 的键空间通知来实现定时任务,它的实现思路是给所有的定时任务设置一个过期时间,等到了过期之后,我们通过订阅过期消息就能感知到定时任务需要被执行了,此时我们执行定时任务即可。


默认情况下 Redis 是不开启键空间通知的,需要我们通过 config set notify-keyspace-events Ex 的命令手动开启,开启之后定时任务的代码如下:


import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPubSub;
import utils.JedisUtils;
public class TaskExample {
    public static final String _TOPIC = "__keyevent@0__:expired"; // 订阅频道名称
    public static void main(String[] args) {
        Jedis jedis = JedisUtils.getJedis();
        // 执行定时任务
        doTask(jedis);
    }
    /**
     * 订阅过期消息,执行定时任务
     * @param jedis Redis 客户端
     */
    public static void doTask(Jedis jedis) {
        // 订阅过期消息
        jedis.psubscribe(new JedisPubSub() {
            @Override
            public void onPMessage(String pattern, String channel, String message) {
                // 接收到消息,执行定时任务
                System.out.println("收到消息:" + message);
            }
        }, _TOPIC);
    }
}


相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
调度
关于定时任务,看着一系列就够了——2.Cron表达式
软件开发定时任务基础—— Cron 表达式介绍
1466 0
关于定时任务,看着一系列就够了——2.Cron表达式
|
8月前
|
JSON 小程序 安全
【经验分享】如何实现小程序日历范围选择功能
【经验分享】如何实现小程序日历范围选择功能
452 9
|
8月前
|
存储 数据处理 调度
Python实现定时任务的方案及其比较
Python实现定时任务的方案及其比较
163 0
|
Java
简单实现一个定时任务
简单实现一个定时任务
143 0
|
存储 Java
【JAVA定时器】四种常见定时器的原理和简单实现,有图易懂 中
【JAVA定时器】四种常见定时器的原理和简单实现,有图易懂 中
303 0
【JAVA定时器】四种常见定时器的原理和简单实现,有图易懂   中
|
Java BI Spring
【JAVA定时器】四种常见定时器的原理和简单实现,有图易懂 上
【JAVA定时器】四种常见定时器的原理和简单实现,有图易懂 上
548 0
【JAVA定时器】四种常见定时器的原理和简单实现,有图易懂   上
|
Java 数据挖掘 Spring
JAVA实现定时任务的方法
JAVA实现定时任务的方法
297 0
|
Java
【JAVA定时器】四种常见定时器的原理和简单实现,有图易懂 下
【JAVA定时器】四种常见定时器的原理和简单实现,有图易懂 下
158 0
|
开发者 微服务
项目中整合定时任务 | 学习笔记
快速学习 项目中整合定时任务
127 0