使用Redisson RLock锁防止定时任务短周期重复执行

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介: 在开发定时任务时,如果任务执行周期较短,可能会导致任务在前一次执行尚未完成时就再次触发,从而产生重复执行的问题。为了解决这个问题,我们可以借助Redisson的RLock锁机制,确保任务只有在前一次执行完成后才能再次执行。本文将介绍如何使用Redisson RLock锁来避免定时任务的重复执行。

RLock.jpg

在开发定时任务时,如果任务执行周期较短,可能会导致任务在前一次执行尚未完成时就再次触发,从而产生重复执行的问题。为了解决这个问题,我们可以借助Redisson的RLock锁机制,确保任务只有在前一次执行完成后才能再次执行。本文将介绍如何使用Redisson RLock锁来避免定时任务的重复执行。

定时任务是一种常见的自动化执行任务的方式,例如在一些app的工单展示中,我们可能需要从数据库中获取到已到生效时间的工单进行发布。然而,如果任务的执行时间超过了1分钟,就会导致任务在前一次执行尚未完成时再次触发,从而产生重复执行的问题。

为了解决这个问题,我们可以使用Redisson的RLock锁机制。Redisson是一个基于Redis的分布式Java对象和服务的框架,它提供了RLock作为分布式可重入锁的实现。RLock允许同一个线程多次获取锁,而不会产生死锁。

RLock介绍

RLock是Redisson提供的分布式可重入锁(Reentrant Lock)的实现。与Python中的RLock类似,Redisson的RLock也具有可重入特性,允许同一个线程多次获取同一把锁而不会产生死锁。

Redisson RLock的特点和使用方式如下:

  • 可重入性:RLock允许同一个线程多次获取锁,而不会导致死锁。每次获取锁时,计数器会递增,直到释放锁的次数与获取锁的次数相等,才会完全释放锁。
  • 高可用性:RLock通过Redis作为分布式锁的后端存储,因此具有良好的可扩展性和高可用性。即使某个Redis节点故障,也可以通过其他可用节点继续提供锁服务。
  • 锁超时机制:RLock支持自动过期释放锁的机制。如果一个线程获取锁后,由于某些原因没有及时释放锁,可以通过设置锁的超时时间来确保在一定时间后自动释放锁,避免长时间占用锁资源。
  • 公平锁:Redisson RLock支持公平锁机制,即在多个线程等待获取锁时,按照获取锁的顺序依次获得锁。这样可以避免线程饥饿的情况发生。
  • 锁续约:RLock支持锁的续约机制,即在获取锁后,可以通过设置锁的过期时间来延长锁的持有时间。这样可以避免因为某个线程持有锁时间过长导致其他线程等待超时。

示例代码

下面是使用Redisson RLock锁来避免定时任务重复执行的示例代码:

import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class Task{
   
   
    //锁过期时间
    private static final Long LOCK_KEY_TIME = 120L;

    public void doJobTask() {
   
   
        //定时任务执行周期较短,为防止数据重复修改,加入锁
        RLock lock = redissonCache.getLock("your_task_name");
        // 尝试获取锁并设定锁的过期时间
        boolean acquired = false;
        try {
   
   
            acquired = lock.tryLock(0, LOCK_KEY_TIME, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
   
   
            log.error("取锁失败");
        }
        if (acquired) {
   
   
            try {
   
   
                // 执行业务逻辑
                handleTask();
            }catch (Exception e) {
   
   
                log.error("处理失败");
                //业务异常处理逻辑
                handleTaskError();
            }finally {
   
   
                // 释放锁
                lock.unlock();
            }

        } else {
   
   
            // 获取锁失败,说明有其他线程或进程正在处理数据
            // 可以进行重试或触发告警机制
            handleLockAcquisitionFailure();
        }
    }
}

在上述示例代码中,我们使用tryLock(0, LOCK_KEY_TIME, TimeUnit.SECONDS)方法来尝试获取锁。其中,等待时间为0秒,即如果锁被其他线程持有,当前线程不会阻塞,而是立即返回获取锁失败。锁的过期时间设置为LOCK_KEY_TIME秒,即如果获取锁后在指定时间内未释放锁,锁将自动过期释放。

通过使用tryLock方法,我们可以更灵活地控制锁的获取,避免任务在短周期内重复执行,并通过锁的过期时间确保锁的释放。

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
3月前
Cron表达式每隔两小时执行一次
Cron表达式每隔两小时执行一次
110 1
|
21天前
|
Java Spring
定时任务里面的任务多线程操作
该内容是关于Spring Boot中配置异步任务和定时任务的代码示例。首先通过`@Configuration`和`@EnableAsync`开启异步支持,然后定义线程池,如使用`ThreadPoolExecutor`并设置核心线程数、最大线程数等参数。接着,在需要异步执行的方法上添加`@Async`注解。此外,通过`@EnableScheduling`开启定时任务,并使用`@Scheduled`定义具体任务和执行周期。若需指定多个线程池,可以创建不同的`Executor` bean,并在`@Async`中指定线程池名称。
19 2
|
7月前
|
Go 数据库
sync.Once-保证运行期间的某段代码只会执行一次
sync.Once-保证运行期间的某段代码只会执行一次
42 0
|
6月前
|
存储 Java 关系型数据库
ShedLock的4种使用方式(分布式定时任务锁)
ShedLock的4种使用方式(分布式定时任务锁)
83 0
|
8月前
|
NoSQL Redis
基于Redis在定时任务里判断其他定时任务是否已经正常执行完的方案
基于Redis在定时任务里判断其他定时任务是否已经正常执行完的方案
60 0
|
11月前
|
Java 测试技术
高并发编程-自定义带有超时功能的锁
高并发编程-自定义带有超时功能的锁
38 0
|
11月前
AS执行时间计算
long start=System.currentTimeMillis();
34 0
|
Java 数据库
定时任务还在用数据库轮询?redission延时队列了解一下
在平常的开发中经常会碰到定时任务处理的场景,比如说用户进行商品购买,下单之后超过半个小时还未进行支付则自动取消该笔订单,订单支付状态由待支付变更为已支付;
定时任务还在用数据库轮询?redission延时队列了解一下
|
Java Maven
java多线程提交,如何按照时间顺序获取线程结果,看完你就懂了 | Java工具类
java多线程提交,如何按照时间顺序获取线程结果,看完你就懂了 | Java工具类
java多线程提交,如何按照时间顺序获取线程结果,看完你就懂了 | Java工具类
JUC(二)JAVA线程池开启,等待全部执行完毕,配合计数器使用,List并发异常解决
JUC(二)JAVA线程池开启,等待全部执行完毕,配合计数器使用,List并发异常解决
JUC(二)JAVA线程池开启,等待全部执行完毕,配合计数器使用,List并发异常解决