1894 字
约 6 分钟
1
JAVA 精髓面试题 · Redis 分布式锁:从基础到 Redisson

Java 复制代码 Java 复制代码 Java 复制代码 Java 复制代码 Java 复制代码 Java 复制代码 Java 复制代码 Java 复制代码 Java 复制代码 Java 复制代码 Java 复制代码 Java 复制代码 Java 复制代码 Java 复制代码 1 1 //获取锁( unique_value可以是UUID等) 2 SET resource_name unique_value NX PX 30000 SET resource_name unique_value NX PX 30000 3 4 4 4 //释放锁( lua脚本中,一定要比较value, 防止误解锁) //释放锁( lua脚本中,一定要比较value, 防止误解锁) 5 if redis.call("get",KEYS [1]) == ARGV [1] then if redis.call("get",KEYS [1]) == ARGV [1] then 6 return redis.call("del",KEYS [1]) return redis.call("del",KEYS [1]) 7 else else 8 return 0 return 0 9 end end 代码解释 zet的底层是一个跳跃表结构 代码解释 zet的底层是一个跳跃表结构 代码解释 zet的底层是一个跳跃表结构 ● set 命令要用 set key value px milliseconds nx ,替代 setnx + expire 需要分两次执行命令的方式 ,保证了原子 性, ● value 要具有唯一性, 可以使用UUID.randomUUID().toString()方法生成 ,用来标识这把锁是属于哪个请求加 的 ,在解锁的时候就可以有依据; ● 释放锁时要验证 value 值, 防止误解锁; ● 通过 Lua 脚本来避免 Check And Set 模型的并发问题, 因为在释放锁的时候因为涉及到多个Redis操作 (利用了eval命令执行Lua脚本的原子性); 加锁代码分析 加锁代码分析 加锁代码分析 加锁代码分析 首先 ,set()加入了NX参数, 可以保证如果已有key存在 ,则函数不会调用成功 ,也就是只有一个客户端能持有 锁 ,满足互斥性 。其次, 由于我们对锁设置了过期时间, 即使锁的持有者后续发生崩溃而没有解锁 ,锁也会因 为到了过期时间而自动解锁( 即key被删除) ,不会发生死锁 。最后, 因为我们将value赋值为requestId ,用来 标识这把锁是属于哪个请求加的 ,那么在客户端在解锁的时候就可以进行校验是否是同一个客户端。 解锁代码分析 将Lua代码传到jedis.eval()方法里, 并使参数KEYS[1]赋值为lockKey ,ARGV[1]赋值为requestId 。在执行的时 候, 首先会获取锁对应的value值 ,检查是否与requestId相等, 如果相等则解锁( 删除key) 。 存在的风险 存在的风险 如果存储锁对应key的那个节点挂了的话 ,就可能存在丢失锁的风险, 导致出现多个客户端持有锁的情况, 这样 就不能实现资源的独享了 Redisson Redisson实现 Redisson是一个在Redis的基础上实现的Java驻内存数据网格( In-Memory Data Grid) 。它不仅提供了一系 列的分布式的Java常用对象, 还实现了可重入锁( Reentrant Lock) 、公平锁( Fair Lock 、联锁 (MultiLock) 、 红锁( RedLock) 、 读写锁( ReadWriteLock) 等, 还提供了许多分布式服务。 Redisson提供了使用Redis的最简单和最便捷的方法 。Redisson的宗旨是促进使用者对Redis的关注分离 (Separation of Concern) ,从而让使用者能够将精力更集中地放在处理业务逻辑上。 Redisson 分布式重入锁用法 Redisson 分布式重入锁用法 Redisson 支持单点模式 、主从模式 、哨兵模式 、集群模式, 这里以单点模式为例: Java 复制代码 Java 复制代码 Java 复制代码 1 // 1.构造redisson实现分布式锁必要的Config 2 Config config = new Config(); 3 config.useSingleServer().setAddress("redis://127.0.0.1:5379").setPassword ("123456").setDatabase(0); 4 // 2.构造RedissonClient 5 RedissonClient redissonClient = Redisson.create(config); 6 // 3.获取锁对象实例( 无法保证是按线程的顺序获取到) 7 RLock rLock = redissonClient.getLock(lockKey); 8 try { 9 /** 10

  • 4.尝试获取锁 11
  • waitTimeout 尝试获取锁的最大等待时间,超过这个值,则认为获取锁失败 12
  • leaseTime 锁的持有时间 ,超过这个时间锁会自动失效( 值应设置为大于业务处理的时 间,确保在锁有效期内业务能处理完) 13 */ 14 boolean res = rLock.tryLock((long)waitTimeout, (long)leaseTime, TimeUnit.SECONDS); 15 if (res) { 16 //成功获得锁,在这里处理业务 17 } 18 } catch (Exception e) { 19 throw new RuntimeException("aquire lock fail"); 20 }finally{ 21 //无论如何 , 最后都要解锁 22 rLock.unlock(); 23 } 可重入锁 1.锁会自动续期,如果业务时间超长,运行期间Redisson会自动给锁重新添加30s,不用担心业务时间,锁自动过去而造成的数据安全问题 2.加锁的业务只要执行完成, 那么就不会给当前的锁续期,即使我们不去主动的释放锁,锁在默认30s之后也会自动的删除

闭锁 闭锁

信号量(Semaphore) 信号量(Semaphore)

Redis集群的主从同步 Redis集群的主从同步 Redis集群的主从同步 Redis集群的主从同步

主从同步优化

分片集群特征: 分片集群特征:

Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发 Redis缓存并发

JAVA 精髓面试题 · Redis 分布式锁:从基础到 Redisson
http://www.clxhxhhr.top/posts/1569/
作者
clxstart
发布于
2026-09-18
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。