当前位置: 首页 > news >正文

Redisson 实现分布式锁简单解析

目录

  • Redisson 实现分布式锁
    • 业务方法:
    • 加锁逻辑
      • LockUtil 工具类
        • 锁余额方法:
          • 工具类代码
          • 枚举代码
      • RedisUtil 工具类
        • tryLock 方法及重载【分布式锁具体实现】
        • Supplier 函数式接口调用分析

Redisson 实现分布式锁

业务方法:

如图,简单的执行一个增加余额的方法,为保证数据一致性,那么可以通过Redisson分布式锁来实现。
在这里插入图片描述

加锁逻辑

LockUtil 工具类

锁余额方法:

在这里插入图片描述

工具类代码
/**
 * @author lujinhong
 * @since  2025/3/25
 */
public class LockUtil {

    /**
     * 锁商家余额
     *
     * @param business 商家id
     * @param supplier 函数式接口;代表一个无参但有返回值的函数,就是代表加锁后要执行的业务逻辑
     * @param lockFail 加锁失败后执行的自定义业务逻辑,这里就是一个简单的抛异常
     */
    public static <T> T businessBalance(Integer business, Supplier<T> supplier, InvokeInter lockFail) {
        return tryLock(RedisKey.LOCK_BUSINESS_BALANCE.getKey(business), supplier, lockFail);
    }
}
枚举代码
/**
 * @author lujinhong
 * @since  2025/3/25
 */
@Getter
@AllArgsConstructor
public enum RedisKey {

    // 商家余额
    LOCK_BUSINESS_BALANCE("lock_business_balance_");

    private final String key;

    public String getKey(Number number) {
        return key + number;
    }
}

RedisUtil 工具类

tryLock 方法及重载【分布式锁具体实现】

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


/**
 * @author lujinhong
 * @since  2025/3/25
 */
@Slf4j
@Component
public class RedisUtil {

    public static RedisUtil _this;

    @Resource
    private RedissonClient redissonClient;

    @PostConstruct
    public void init() {
        _this = this;
    }

    /**
     * 设置分布式锁
     *
     * @param key      就是上面用商家id生成的一个key
     * @param supplier 函数式接口,加锁后要执行的业务逻辑
     * @param lockFail 加锁失败后执行的业务逻辑:这里是抛异常
     */
    public static <T> T tryLock(String key, Supplier<T> supplier, InvokeInter lockFail) {
        return tryLock(key, supplier, lockFail, 10, TimeUnit.SECONDS);
    }



    /**
     * 设置分布式锁--具体实现
     * <p>
     * 注意事项1:.getLock(key):用商家Id作为key生成一个rLock对象,底层代码是通过new来创建实例的,也就是说不同线程操作同一个商家获取到的是不同的RLock实例,
     * -----------重点来了:虽然 RLock 实例在 Java 层是不同的,但是它们 指向同一个 Redis 锁,这个锁的标识是由 key(比如 LOCK_BUSINESS_BALANCE:1001)决定的。
     * --------------------所以才需要在加锁之前,判断当前这个锁实例是否被其他线程占用了等判断--> if (lock.isLocked() && !lock.isHeldByCurrentThread())
     * <p>
     * 锁实例:RLock 是一个 Java 对象,代表分布式锁,它操作 Redis 中的实际锁资源。
     * 锁资源:是 Redis 中的一个 key,用于标识是否已被某个线程持有,实际上是分布式锁的底层实现。
     * <p>
     * 获取锁,其实就是当前线程获得了对某个共享资源的独占访问权限
     * <p>
     * lock.isHeldByCurrentThread() 的底层实现依赖于 Redis 中 锁的 value 存储了持有锁的线程的 ID。该方法通过查询 Redis 锁的 value,并与当前线程的 ID 比较,来判断当前线程是否持有该锁
     *
     * @param key      用来生成 RLock 锁实例的key
     * @param supplier 函数式接口,在加锁成功后执行的业务逻辑
     * @param lockFail 加锁失败后执行的业务逻辑
     * @param amount   当前线程在获取锁时最多等待的时间【注意是获取锁的时间,不是获取到该锁后锁的存活时间】,就是给你多少时间去获取锁
     * @param unit     时间单位
     */
    public static <T> T tryLock(String key, Supplier<T> supplier, InvokeInter lockFail, long amount, TimeUnit unit) {

        // 创建一个 redisson 分布式锁的锁实例:
        // 这个实例并不是直接获取Redis里的锁,而是一个Java对象,它是 Redisson 对 Redis 分布式锁的封装,用于后续操作:
        // 如 加锁tryLock()、释放锁unlock()、查询锁状态 isLocked()
        RLock lock = _this.redissonClient.getLock(key);

        try {
            // lock.isLocked():判断的是 Redis 中该 key(锁资源)是否已经被其他线程或进程获取。
            // !lock.isHeldByCurrentThread():判断当前线程是否持有该锁,就是通过 Redis 中的 key 来检查是否是当前线程获得了该锁
            if (lock.isLocked() && !lock.isHeldByCurrentThread()) {
                if (lockFail == null) {
                    // 直接抛异常
                    throw BizException.newInstance(ErrorCode.BUSY);
                }
                // 如果有自定义的加锁失败逻辑,则执行
                lockFail.invoke();
            }
            // 真正的加锁:在指定时间(amount)内获取锁,获取不到则返回false;
            // 问题:lock.tryLock获取到锁之后,redis内部是做了什么操作:其实就是操作了一句 setNx 命令而已。
            else if (lock.tryLock(amount, unit)) {
                try {
                    // 执行具体的业务逻辑
                    return supplier.get();
                } finally {
                    // 释放锁
                    lock.unlock();
                }
            } else {
                // 上面没获取到锁,则报错
                if (lockFail == null) {
                    // 默认就抛这个异常
                    throw BizException.newInstance(ErrorCode.BUSY);
                }
                // 如果有自定义的异常处理,则执行
                lockFail.invoke();
            }
            return null;
        } catch (InterruptedException e) {
            throw BizException.newInstance(ErrorCode.BUSY);
        }
    }

}

Supplier 函数式接口调用分析

在这里插入图片描述

相关文章:

  • node-red dashboard
  • C++:函数(通识版)
  • “11.9元“引发的系统雪崩:Spring Boot中BigDecimal反序列化异常全链路狙击战 ✨
  • 颠覆未来:解锁ChatGPT衍生应用的无限可能(具体应用、功能、付费模式与使用情况)
  • 【MySQL】实战篇—项目需求分析:ER图的绘制与关系模型设计
  • air780eq 阿里云
  • CentOS 7 搭建基于匿名用户的 FTP 服务
  • Trae初使用心得(Java后端)
  • 代码随想录刷题day52|(二叉树篇)106.从中序与后序遍历序列构造二叉树(▲
  • 基于 Python 的自然语言处理系列(61):RAG Fusion介绍
  • Rust从入门到精通之精通篇:26.性能优化技术
  • 软件性能效率测试工具有哪些?专业第三方软件检测机构推荐
  • Linux上位机开发实践(访问IPCam设备)
  • 23种设计模式-责任链(Chain of Responsibility)设计模式
  • Redis的三种集群模式
  • TDengine 3.3.2.0 集群报错 Post “http://buildkitsandbox:6041/rest/sql“
  • 过滤器的执行顺序
  • Python 字符串正则表达式详解
  • 第 1 章 | 开篇词:Dapp安全 区块链安全 Web3安全 区块链合约一旦部署,安全就是生死线
  • AI加速,制造企业如何用数据驱动质量管理数字化变革?
  • 物流公司网站开发与淘宝对接 在淘宝卖家中心显示物流信息/免费seo工具汇总
  • 重庆高端网站seo/视频号排名优化帝搜软件
  • 济南网站建设伍际网络/百度怎么发帖做推广
  • 东莞建站模板后台/百度电视剧风云榜
  • 网站开发 工期安排/网页设计制作网站模板图片
  • 有个可以做图片的网站/如何做好seo基础优化