Redis分布式锁中8个常见面试题小结

来源:这里教程网 时间:2026-03-09 11:11:16 作者:
???? 1. 为什么需要分布式锁????? 2. 最简单的分布式锁怎么写?(错误示范)⚠️ 问题在哪里????? 3. 怎么设置过期时间?(还是不对)⚠️ 问题:两步不是原子的!???? 4. 正确写法是怎样的?✅ 关键点:???? 5. 锁的value为什么不能用"1"?场景演示:???? 6. 业务没执行完,锁过期了怎么办?方案1:设置合理的过期时间方案2:自动续期(看门狗)???? 7. Redis主从切换会丢锁吗?场景:解决方案:???? 8. 实际开发用什么?(不要造轮子!)???? 面试对比表❓ 面试常见问题Q1: "说一下Redis分布式锁的实现原理"Q2: "Redis锁和ZooKeeper锁的区别?"Q3: "怎么实现可重入锁?"???? 记住三句话???? 快速检查清单

???? 1. 为什么需要分布式锁?

场景:双11秒杀,10000人抢100个商品

单机锁不行:秒杀系统有10台服务器,每台都有自己的内存,锁不住其他服务器需要共享的锁:所有服务器都能访问的锁 → Redis分布式锁

???? 2. 最简单的分布式锁怎么写?(错误示范)

// ❌ 新手最容易写的错误代码 public boolean lock(String key) { String result = jedis.setnx(key, "1"); // 尝试加锁 return result == 1; // 1表示加锁成功 } public void unlock(String key) { jedis.del(key); // 删除锁 }

⚠️ 问题在哪里?

    死锁风险:如果程序崩溃,锁永远不释放误删别人锁:A的锁超时释放,B获得锁,A醒来删了B的锁

???? 3. 怎么设置过期时间?(还是不对)

// ❌ 这个也有问题 public boolean lock(String key, int seconds) { // 两步操作:1.加锁 2.设置过期时间 Long result = jedis.setnx(key, "1"); if (result == 1) { jedis.expire(key, seconds); // 设置过期 return true; } return false; }

⚠️ 问题:两步不是原子的!

如果setnx成功,但expire前程序崩溃 → 锁变永久的!

???? 4. 正确写法是怎样的?

// ✅ 正确的加锁(一步完成) public boolean lock(String key, String value, int seconds) { // 一条命令完成:加锁+设置过期时间 String result = jedis.set(key, value, "NX", "EX", seconds); return "OK".equals(result); } // ✅ 安全的解锁 public void unlock(String key, String value) { // 用Lua脚本保证原子操作:检查值再删除 String script = "if redis.call('get', KEYS[1]) == ARGV[1] then " + " return redis.call('del', KEYS[1]) " + "else " + " return 0 " + "end"; jedis.eval(script, 1, key, value); }

✅ 关键点:

    一条命令SET key value NX EX secondsvalue用唯一标识:UUID或线程ID原子删除:用Lua脚本检查再删除

???? 5. 锁的value为什么不能用"1"?

// ❌ 错误:大家value都一样 jedis.set("lock", "1", "NX", "EX", 10); // ✅ 正确:每人一个唯一标识 String myId = UUID.randomUUID().toString(); jedis.set("lock", myId, "NX", "EX", 10);

场景演示:

线程A:获得锁,value="A123",超时10秒
线程A:执行了15秒(锁在第10秒已过期)
线程B:获得锁,value="B456"
线程A:终于执行完,要删除锁 → 删了线程B的锁!❌

???? 6. 业务没执行完,锁过期了怎么办?

方案1:设置合理的过期时间

// 评估业务时间,设置更长过期 jedis.set("lock", uuid, "NX", "EX", 30); // 设置30秒

方案2:自动续期(看门狗)

// 启动一个线程,定期续期 new Thread(() -> { while (业务没执行完) { Thread.sleep(8000); // 8秒续一次 // 如果是自己的锁,就延长过期时间 jedis.expire("lock", 10); } }).start();

???? 7. Redis主从切换会丢锁吗?

会!这是Redis分布式锁的最大问题

场景:

1. 线程A在主节点获得锁
2. 主节点宕机(锁数据还没同步到从节点)
3. 从节点变成新主节点
4. 线程B在新主节点获得"相同"的锁
结果:A和B同时持有了锁!

解决方案:

    用RedLock算法:在多个Redis实例上加锁用ZooKeeper:更适合分布式锁接受风险:业务上做幂等处理

???? 8. 实际开发用什么?(不要造轮子!)

// 使用Redisson框架(最省心) RedissonClient redisson = Redisson.create(); RLock lock = redisson.getLock("myLock"); try { lock.lock(); // 加锁(自动续期) // 执行业务... } finally { lock.unlock(); // 解锁 }

???? 面试对比表

方案优点缺点适用场景Redis单节点简单、快主从切换丢锁测试环境、不重要的锁RedLock相对可靠实现复杂、性能差重要的业务锁Redisson功能全、自动续期依赖框架推荐的生产方案ZooKeeper最可靠性能较差强一致性的场景

❓ 面试常见问题

Q1: "说一下Redis分布式锁的实现原理"

:"用SET命令的NX和EX参数,NX保证只有一个能设置成功,EX设置过期时间防止死锁。删除时用Lua脚本原子操作,避免删别人锁。"

Q2: "Redis锁和ZooKeeper锁的区别?"

Redis:AP系统,性能好,但可能丢锁ZooKeeper:CP系统,可靠但性能差选择:要高性能用Redis,要可靠性用ZooKeeper

Q3: "怎么实现可重入锁?"

:"在value里记录线程ID和重入次数。加锁时如果是同一线程,计数+1;解锁时计数-1,计数为0才真正删除锁。"

???? 记住三句话

    加锁要原子SET key uuid NX EX seconds解锁要安全:用Lua脚本先检查再删除生产别造轮子:直接用Redisson

???? 快速检查清单

你的分布式锁:

设置过期时间了吗?value是唯一的吗?删除前检查value了吗?考虑锁续期了吗?知道主从切换会丢锁吗?

满足这5条,面试官就难不倒你了!

到此这篇关于Redis分布式锁中8个常见面试题小结的文章就介绍到这了,

相关推荐

热文推荐