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

java | 基于Redis的分布式锁实现①

前言

首先,为了确保分布式锁可用,我们至少要确保锁的实现同时满足以下四个条件:

  1. 互斥性。在任意时刻,只有一个客户端能持有锁。
  2. 不会发生死锁。即使有一个客户端在持有锁的期间崩溃而没有主动解锁,也能保证后续其他客户端能加锁。
  3. 具有容错性。只要大部分的Redis节点正常运行,客户端就可以加锁和解锁。
  4. 加锁和解锁必须是同一个客户端,客户端自己不能把别人加的锁给解了。

实现

  • 首先引入jedis组件依赖,pom中添加如下配置:
        <dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId></dependency>
  • 加锁代码
    private static final String LOCK_SUCCESS = "OK";/*** 该加锁方法仅针对单实例 Redis 可实现分布式加锁* 对于 Redis 集群则无法使用* 支持重复,线程安全** @param lockKey      加锁键* @param requestId    加锁客户端唯一标识* @param milliseconds 锁过期时间:此处使用的单位为 px-毫秒数,若需要单位为秒,则改用parms.ex(int seconds)* @return*/public Boolean tryLock(String lockKey, String requestId, long milliseconds) {SetParams parms = new SetParams();parms.px(milliseconds);return redisTemplate.execute((RedisCallback<Boolean>) redisConnection -> {Jedis jedis = (Jedis) redisConnection.getNativeConnection();String result = jedis.set(lockKey, requestId, parms);return LOCK_SUCCESS.equals(result);});}

第一个参数:加锁的key,当前没有锁(key不存在),那么就进行加锁操作,已有锁存在,不做任何操作。
第二个参数:为确保安全性,需要key和value都一致才会解锁。
第二个参数:(看代码注释)


  • 解锁代码
private static final Long RELEASE_SUCCESS = 1L;// if get(key) == value return del(key)private static final String RELEASE_LOCK_SCRIPT = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";/*** 与 tryLock 相对应,用作释放锁** @param lockKey   加锁键* @param requestId 加锁客户端唯一标识* @return*/public Boolean releaseLock(String lockKey, String requestId) {return redisTemplate.execute((RedisCallback<Boolean>) redisConnection -> {Jedis jedis = (Jedis) redisConnection.getNativeConnection();Object result = jedis.eval(RELEASE_LOCK_SCRIPT, Collections.singletonList(lockKey),Collections.singletonList(requestId));return RELEASE_SUCCESS.equals(result);});}

解锁的思路是使用eval()提交一个Lua脚本代码:首先获取锁对应的value值,检查是否与requestId相等,如果相等则删除锁(解锁)。
那为什么使用eval()?在eval命令执行Lua代码的时候,Lua代码将被当成一个命令去执行,直到eval命令执行完成,Redis才会执行其他命令。也就是说,这个操作满足原子性,保证了安全性。

http://www.lryc.cn/news/6860.html

相关文章:

  • 十六、基于FPGA的CRC校验设计实现
  • 2022爱分析 · DataOps厂商全景报告 | 爱分析报告
  • 京东前端react面试题及答案
  • TongWeb8数据源相关问题
  • 关于最近大热的AI,你怎么看?
  • 25.架构和软件产品线
  • Seata-server 源码学习(一)
  • 2023新华为OD机试题 - 斗地主(JavaScript)
  • 素数相关(结合回文数,合数)线性筛素数(欧拉筛法)Euler【算法模板笔记】
  • 1.7配置OSPF手动汇总
  • 多线程下载工具axel的安装和使用
  • 大数据专业职业前景如何
  • 拉格朗日乘数法在原材料选择问题上的具体应用
  • 零信任-腾讯零信任iOA介绍(4)
  • 标准的maven依赖包应该包含哪些东西?
  • 网络安全-Nmap
  • 【物联网】mqtt初体验
  • 2023年阿里云活动有哪些实例规格的云服务器?如何选择这些实例规格
  • 深入理解 Handler(java 层 + native 层)
  • 初步认识操作系统(Operator System)
  • Android—HTTPS部署自签名证书
  • java基于springboot+vue微信小程序的学生健康管理
  • 金三银四丨黑蛋老师带你剖析-漏洞岗
  • pinia实战 购物车(自定义插件实现pinia持久化)
  • idea使用本地代码远程调试线上运行代码---linux环境
  • Java 基础面试题——集合
  • 编程思想、方法论和架构模式的应用
  • Vue|事件处理
  • css书写方式
  • Python网络爬虫 学习笔记(2)BeaufitulSoup库