• Redis实现分布式锁(9)


    1.Redis分布式锁实现思路

    Redis实现分布式锁基于SetNx命令,因为在Redis中key是保证是唯一的。所以当多个线程同时的创建setNx时,只要谁能够创建成功谁就能够获取到锁。

    Set 命令 每次set时,可以修改原来旧值;
    SetNx命令 每次SetNx检查该key是否已经存在,如果已经存在的话不会执行任何操作。返回为0 如果已经不存在的话直接新增该key。
    返回值: 1-新增key成功 0-失败

    获取锁的时候:当多个线程同时创建SetNx k,只要谁能够创建成功谁就能够获取到锁。
    释放锁:可以对该key设置一个有效期可以避免死锁的现象。

    2.分布式锁的应用场景

    1. 分布式任务调度平台保证任务的幂等性。
    2. 分布式全局id的生成

    3.Redis分布式锁核心代码

    封装的JedisUtil类可查看前面代码或者 完整的github项目 【springboot-redis(redis-lock)】

    3.1 封装获取RedisLockUtil 工具类

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    import java.util.UUID;
    
    /**
     * @author 若成风
     * @description
     * @date 2022/9/7 23:45
     * @copyright (c) 2022, all rights reserved
     **/
    @Component
    public class RedisLockUtil {
        @Autowired
        private JedisUtil jedisUtil;
        private static final int setnxSuccss = 1;
    
        /**
         *  获取锁
         *  timeOut 时间为毫秒
         *  示例: getLock("lockKey" , 3000, 5000)
         *  申请尝试加锁,最大等待时间3秒,上锁5秒后自动解锁
         * @param lockKey           定义锁的key
         * @param lockWaitTimeOut   申请锁的最大等待时间,超过则申请锁失败
         * @param lockTimeOut       锁的超时时间
         * @return
         */
        public String getLock(String lockKey, int lockWaitTimeOut, int lockTimeOut) {
            // 获取Redis连接
            // 定义没有获取锁的超时时间
            Long endTimeOut = System.currentTimeMillis() + lockWaitTimeOut;
            while (System.currentTimeMillis() < endTimeOut) {
                String lockValue = UUID.randomUUID().toString();
                // 如果在多线程情况下谁能够setnx 成功返回0 谁就获取到锁
                Long nx = jedisUtil.setnx(lockKey, lockValue, lockTimeOut / 1000);
                if (setnxSuccss == nx) {
                    return lockValue;
                }
                // 否则情况下 在超时时间内继续循环
            }
            return null;
        }
    
        /**
         * 释放锁 其实就是将该key删除
         * @return
         */
        public Boolean unLock(String lockKey, String lockValue) {
            // 确定是对应的锁 ,才删除
            if (StringUtils.isNotBlank(lockValue) && lockValue.equals(jedisUtil.get(lockKey))) {
                return jedisUtil.del(lockKey) > 0 ? true : false;
            }
            return false;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    3.2测试使用分布式锁

    import com.redmaple.common.util.RedisLockUtil;
    import com.redmaple.service.OrderService;
    import org.apache.commons.lang3.StringUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    /**
     * @author 若成风
     * @description
     * @date 2022/9/8 23:06
     * @copyright (c) 2022, all rights reserved
     **/
    @Service
    public class OrderServiceImpl implements OrderService {
        @Autowired
        private RedisLockUtil redisLockUtil;
        private String lockKey = "redmaple_lock";
    
        @Async("myThreadPool")
        @Override
        public void testService() {
            // 1.获取锁
            String lockValue = redisLockUtil.getLock(lockKey, 500, 60000);
            try {
                if (StringUtils.isEmpty(lockValue)) {
                    System.out.println(Thread.currentThread().getName() + ",获取锁失败!");
                    return;
                }
                // 2.获取锁成功执行业务逻辑
                System.out.println(Thread.currentThread().getName() + ",获取成功,lockValue:" + lockValue);
                Thread.sleep(2000);
            } catch (Exception e) {
                log.error("分布式锁", e);
            } finally {
                // 防止代码执行完成后,或发生异常后,主动释放锁
                // 3.释放lock锁
                redisLockUtil.unLock(lockKey, lockValue);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    @RestController
    public class RedisLockController {
    
        @Autowired
        private OrderService orderService;
    
        @GetMapping("/testRedisLock")
        public String testRedisLock() {
            System.out.println("=====  start  ======");
            for (int i = 0; i < 10; i++) {
                orderService.testService();
            }
            return "===  success  ===";
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    如果该文章能够帮助到你,希望麻烦一键三连下,谢谢

  • 相关阅读:
    MySQL Router重装后重新连接集群进行引导出现的——此主机中之前已配置过的问题
    阿里云服务器不能访问网络之安装mysql 提示连接超时
    springboot和vue:一、cs/bs区别+maven介绍与其仓库配置
    SSM17:注解开发管理第三方bean
    玩转数据-大数据-Flink SQL 中的时间属性
    基于python的pdf2word(可以批量转换)
    【毛毛讲书】【混合信号】如何更好地设计激励措施?
    图的应用:关键路径 ← PPT
    Sentinel与OpenFeign 服务熔断那些事
    C++:红黑树
  • 原文地址:https://blog.csdn.net/qq_34846877/article/details/126755863