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

redis分布式锁的实际业务使用和底层基本原理 对比 lock trylock

文章目录

  • 前言
  • 业务代码
  • 加锁背后
  • lock(有参、无参) trylock(有参、无参)的区别
  • 什么是watchDog
  • 总结

前言

本篇文章将通过一个具体的业务代码 带你理解分布式锁在redis中的实际数据结构 以及为何能作为分布式锁的原因。同时本文会比较lock (有参、无参)trylock(有参、无参)这四种的区别。

业务代码

   private ResultDto Pay(String payPasselNo, UserDto userDTO) {ResultDto finalResult = Builder.buildResult();log.info("支付开始");RLock lock = null;  // ← Redisson分布式锁声明try {List<String> list = getPaymentList(payPasselNo)// 1.根据key加锁 ← 获取锁对象String lockKey = "lock:salary:submit:" + payPasselNo;lock = redissonClient.getLock(lockKey);// 2.尝试获取锁 ← 非阻塞获取boolean success = lock.tryLock();if (!success) {log.info("加锁失败[{}]", payPasselNo);finalResult.append("失败");finalResult.failIncrease();return finalResult;  // ← 获取锁失败直接返回}// 3.执行业务逻辑 ← 在锁保护下执行// ... 业务处理代码 ...finalResult.setSuccess(true);} catch (Exception e) {// ... 异常处理 ...}  finally {// 4.确保释放锁 ← 在finally块中释放try {if (ObjectUtil.isNotEmpty(lock)) {lock.unlock();  // ← 释放锁}} catch (Exception e) {log.error(e.getMessage(), e);}}log.info("支付结束");return finalResult;}

这是一个模拟支付的业务代码 根据支付批次号payPasselNo生成key 去进行支付。(已经抹去不相关的业务代码)

数据流转分析:

1、获取锁 lock = redissonClient.getLock(lockKey);
2、加锁 lock.tryLock();
3、执行业务代码
4、解锁 lock.unlock();

那么在tryLock背后 redis究竟做了什么呢?

加锁背后

在这里插入图片描述
可以看到 当我们执行tryLock 并且redis加锁成功后 redis创建了一个hash类型的数据 用于存储锁的元数据(线程 ID、计数)

"a4344e6f-132a-47aa-b077-b80a7b7c2dcb:1"就是默认创建的线程ID

“1” 代表的就是锁被重入了1次

这下你知道了背后的数据结构是什么了吧,就是一个hash结构每次加锁就将计数+1 释放锁就计数-1 到期后锁就会消失。
好的,接下来我们要去区分下lock(有参、无参) trylock(有参、无参)这四种的区别。

lock(有参、无参) trylock(有参、无参)的区别

方法是否阻塞是否自动释放是否支持 Watchdog
lock()一直阻塞否(必须手动 unlock)是(30 秒 + 自动续期)
lock(leaseTime)阻塞直到拿到锁是(过期自动释放)否(不启动 Watchdog)
tryLock(waitTime, leaseTime)最多阻塞 waitTime是(过期自动释放)否(不续期)
tryLock()非阻塞(立即返回)否(必须 unlock)是(30 秒 + 自动续期)

怎么去记忆 ? 赋值了参数 就不启动watchDog机制 没有赋值 就会启动watchDog 自动延期锁

不同的业务场景需要使用不同的方式

业务场景推荐方法
必须执行,能等多久都行(例如批量发工资 不能失败、不能跳过、不能并发执行)lock()
试一下能不能抢到,不行就算了(高并发的抢单)tryLock()
只等 N 秒就放弃,抢到后 N 秒内必须完成tryLock(wait, lease, unit)

什么是watchDog

在成功加锁(lock/tryLock)后,Redisson 会启动一个后台线程,每隔 10 秒执行一次 Lua 脚本,为 Redis 中的锁续期

lua脚本如下

// 首先判断当前线程是否持有锁 如果是就延期
if redis.call('hexists', KEYS[1], ARGV[1]) == 1 thenreturn redis.call('pexpire', KEYS[1], ARGV[2])
end

源码如下

    protected CompletionStage<Boolean> renewExpirationAsync(long threadId) {return this.evalWriteAsync(this.getRawName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN, "if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then redis.call('pexpire', KEYS[1], ARGV[1]); return 1; end; return 0;", Collections.singletonList(this.getRawName()), this.internalLockLeaseTime, this.getLockName(threadId));}

总结

你是否已经了解了redis分布式锁是如何实现的呢?

http://www.lqws.cn/news/150139.html

相关文章:

  • Linux环境-通过命令查看zookeeper注册的服务
  • DisplayPort 2.0协议介绍(1)
  • x86 汇编中的【条件跳转指令】:从基础到扩展的全面解析(查表版)
  • 新建网站部署流程
  • 力扣面试150题--被围绕的区域
  • ArcGIS Pro 3.4 二次开发 - 公共设施网络
  • 实时数据仓库是什么?数据仓库设计怎么做?
  • Neovim - 常用插件,提升体验(三)
  • [论文阅读] 人工智能+项目管理 | 当 PMBOK 遇见 AI:传统项目管理框架的破局之路
  • flutter 中Stack 使用clipBehavior: Clip.none, 超出的部分无法响应所有事件
  • 深度学习在非线性场景中的核心应用领域及向量/张量数据处理案例,结合工业、金融等领域的实际落地场景分析
  • 电子行业AI赋能软件开发经典案例——某金融软件公司
  • 软考 系统架构设计师系列知识点之杂项集萃(82)
  • Qt实现一个悬浮工具箱源码分享
  • 【HarmonyOS 5】 社交行业详解以及 开发案例
  • 使用 HTML +JavaScript 从零构建视频帧提取器
  • vue3+ts实现百度地图鼠标绘制多边形
  • Oracle-高频业务表的性能检查
  • 深度解析地质灾害风险普查:RS与GIS技术在泥石流、滑坡灾害中的应用,ArcGIS数据管理、空间数据转换、专题地图制作、DEM分析及实战案例分析
  • Transformer实战——词嵌入技术详解
  • 基于Qt的app开发第十三天
  • Java爬虫技术详解:原理、实现与优势
  • 【设计模式-4.11】行为型——解释器模式
  • JMeter 实现 MQTT 协议压力测试 !
  • MySQL中的部分问题(1)
  • kafka入门学习
  • windows10 php报错
  • 【设计模式】门面/外观模式
  • JVM中的各类引用
  • 【Rust宏编程】Rust有关宏编程底层原理解析与应用实战