定时器+redis分布式锁、定时器+redisson框架分布式锁

定时器+redis分布式锁

 

在xml中添加:

<task:annotation-driven/>

 

1. 不带锁的定时器:

 

 

2. 带redis分布式锁的定时器:

原理:设置锁的lokkey,值为当前毫秒值+超时毫秒值,redis的setnx方法为,如果不存在lokkey,返回1并设置lokkey,返回0,代表已存在锁

 

代码

 

 

 

3.上面的方法虽然好,但是如果在设置锁的有效期之前,tomcat异常关闭,比如:杀死tomcat进程,在redis中已经存在锁,这种情况会出现死锁,所以需要进行改进

 

优化版:设置锁的lokkey,值为当前毫秒值+超时毫秒值,redis的setnx方法为,如果不存在lokkey,返回1并设置lokkey,返回0,代表已存在锁

返回0时,判断当前时间是否为空&&是否 > redis的value值 lockvalueA

{

不为空且大于:使用getset方法,设置值为当前毫秒+超时毫秒,返回旧值 lockvalueB,判断lockvalueB是否为空 || (lockvalueB不为空且lockvalueA==lockvalueB)

    {

         lockvalueB为空:代表走到这一步,别的tomcat已经执行了一遍代码并且释放了锁

         lockvalueB不为空且lockvalueA==lockvalueB:代表开启定时后第一次执行此代码

         lockvalueA != lockvalueB:代表别的tomcat已经在执行此代码,并且锁还未被释放

    }

不为空且小于:结束

为空:结束

}

 

 

代码

@Scheduled(cron="0 */1 * * * ?")
    public void closeOrderTaskV3(){
        log.info("关闭订单定时任务启动");
        long lockTimeout = Long.parseLong(PropertiesUtil.getProperty("lock.timeout","5000"));
        Long setnxResult = RedisShardedPoolUtil.setnx(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK,String.valueOf(System.currentTimeMillis()+lockTimeout));
        if(setnxResult != null && setnxResult.intValue() == 1){
            closeOrder(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);
        }else{
            //未获取到锁,继续判断,判断时间戳,看是否可以重置并获取到锁
            String lockValueStr = RedisShardedPoolUtil.get(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);
            if(lockValueStr != null && System.currentTimeMillis() > Long.parseLong(lockValueStr)){
                String getSetResult = RedisShardedPoolUtil.getSet(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK,String.valueOf(System.currentTimeMillis()+lockTimeout));
                //再次用当前时间戳getset。
                //返回给定的key的旧值,->旧值判断,是否可以获取锁
                //当key没有旧值时,即key不存在时,返回nil ->获取锁
                //这里我们set了一个新的value值,获取旧的值。
                if(getSetResult == null || (getSetResult != null && StringUtils.equals(lockValueStr,getSetResult))){
                    //真正获取到锁
                    closeOrder(Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);
                }else{
                    log.info("没有获取到分布式锁:{}",Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);
                }
            }else{
                log.info("没有获取到分布式锁:{}",Const.REDIS_LOCK.CLOSE_ORDER_TASK_LOCK);
            }
        }
        log.info("关闭订单定时任务结束");
    }

 

 

 

 

定时器+redisson框架分布式锁

 

使用这个方法代码会简单很多

在pom.xml中添加:

<dependency>
      <groupId>org.redisson</groupId>
      <artifactId>redisson</artifactId>
      <version>2.9.0</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.dataformat</groupId>
      <artifactId>jackson-dataformat-avro</artifactId>
      <version>2.9.0</version>
    </dependency>

 

 

RedissonManager类

@Component
@Slf4j
public class RedissonManager {

    private Config config = new Config();

    private Redisson redisson = null;

    public Redisson getRedisson() {
        return redisson;
    }

    private static String redis1Ip = PropertiesUtil.getProperty("redis1.ip");
    private static Integer redis1Port = Integer.parseInt(PropertiesUtil.getProperty("redis1.port"));
    private static String redis2Ip = PropertiesUtil.getProperty("redis2.ip");
    private static Integer redis2Port = Integer.parseInt(PropertiesUtil.getProperty("redis2.port"));

    @PostConstruct
    private void init(){
        try {
            config.useSingleServer().setAddress(new StringBuilder().append(redis1Ip).append(":").append(redis1Port).toString());

            redisson = (Redisson) Redisson.create(config);

            log.info("初始化Redisson结束");
        } catch (Exception e) {
            log.error("redisson init error",e);
        }
    }



}

 

 

### Redis 分布式锁自动续期方法 为了防止因网络延迟或其他原因导致的锁提前失效问题,Redisson 提供了一种机制,在线程成功获取到锁之后,会启动一个 watch dog 看门狗后台线程。该线程每间隔一定时间(默认为30秒的一半即15秒)检查当前线程是否仍然持有锁,如果是则不断延长锁 key 的生存时间[^2]。 这种做法有效解决了由于锁超时而引发的数据不一致风险,同时也简化了开发人员对于锁管理的操作复杂度。下面给出一段基于 Java 使用 Redisson 客户端库实现分布式锁及其自动续期功能的具体代码实例: ```java import org.redisson.Redisson; import org.redisson.api.RLock; import org.redisson.api.RedissonClient; import org.redisson.config.Config; public class DistributedLockExample { public static void main(String[] args) throws InterruptedException { Config config = new Config(); config.useSingleServer().setAddress("redis://127.0.0.1:6379"); // 创建 Redisson 客户端连接对象 RedissonClient redisson = Redisson.create(config); try { RLock lock = redisson.getLock("myDistributedLock"); // 尝试加锁,默认等待时间为-1毫秒(无限), 锁的有效时间为10秒钟 boolean isLocked = lock.tryLock(-1, 10, TimeUnit.SECONDS); if (isLocked){ System.out.println(Thread.currentThread().getName() + " acquired the distributed lock."); // 执行受保护的关键业务逻辑... Thread.sleep(8 * 1000); //模拟长时间运行的任务 // 不需要显式调用unlock(),因为有watchdog负责自动续约直到任务完成. }else{ System.out.println(Thread.currentThread().getName()+" failed to acquire the distributed lock."); } } finally { // 关闭资源 redisson.shutdown(); } } } ``` 上述例子展示了如何配置并使用 Redisson 来处理分布式的锁定需求,并且得益于内置的支持,无需开发者额外编写复杂的定时器或监控程序即可轻松达成自动续期的效果。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值