- 各个微服务使用各自的锁,但JVM1和JVM2之间是隔离开的,无法实现多个微服务共用一把锁;

- 不同的JVM的线程,必须跨越微服务的限制,都共同获取同一把锁


- 什么是分布式锁?


基于redis实现分布式锁
- 基于Redis获取锁的全流程,要保证获取锁互斥,要设置过期时间,要走非阻塞式的获取锁方式;

- 案例一:非阻塞获取锁(可重试1次),设置获取锁时的超时时间;

java
// 定义一个简单的Redis分布式锁类,实现ILock接口
//(ILock是自定义的锁接口,通常包含tryLock、unlock等方法)
public class SimpleRedisLock implements ILock{
// 锁的名称(用于区分不同业务场景的锁,比如"order:lock"代表订单业务的锁)
private String name;
// Redis操作模板(Spring提供的Redis客户端工具,用于操作Redis)
private StringRedisTemplate stringRedisTemplate;
// 构造方法:初始化锁名称和RedisTemplate
public SimpleRedisLock(String name, StringRedisTemplate stringRedisTemplate) {
this.name = name;
this.stringRedisTemplate = stringRedisTemplate;
}
// 锁的Key前缀(用于在Redis中区分锁的Key,避免与其他Key冲突)
private static final String KEY_PREFIX = "lock:";
// 重写ILock接口的tryLock方法:尝试获取锁,超时时间由timeoutSec指定
@Override
public boolean tryLock(long timeoutSec) {
// 1. 获取当前线程的ID(作为锁的Value,用于后续释放锁时验证"锁的持有者")
long threadId = Thread.currentThread().getId();
// 2. 尝试在Redis中创建锁:
// - 使用setIfAbsent方法(对应Redis的SETNX命令):只有当Key不存在时才会设置成功(保证原子性)
// - Key:由前缀+锁名称组成(比如"lock:order")
// - Value:当前线程ID(转成字符串,用于标识锁的持有者)
// - 同时设置超时时间timeoutSec(避免服务宕机后锁永久存在)
Boolean success = stringRedisTemplate.opsForValue()
.setIfAbsent(KEY_PREFIX + name, threadId + "", timeoutSec, TimeUnit.SECONDS);
// 3. 返回是否获取锁成功:用Boolean.TRUE.equals避免success为null时的空指针
return Boolean.TRUE.equals(success);
}
}
// 重写ILock接口的unlock方法:释放锁
@Override
public void unlock() {
// 直接删除Redis中对应的锁Key
stringRedisTemplate.delete(KEY_PREFIX + name);
}

- 代码加锁

- 两个微服务,只有一个获取到了锁

- 若线程1获取到了锁,遇到了阻塞情况,运行时间超过了过期时间,则线程1业务没执行完,就被线程2抢到了锁,无法保证业务的一致性;
- 前面阻塞的线程1执行完了之后,又释放了线程2的锁,线程2的业务也无法保证业务的一致性;

改进后方案,解决了释放别人锁的问题(要求只能释放自己的锁)


- 释放锁时,要判断加锁时的标识是否一致

- 极端条件下,在判断锁和释放锁中间发生阻塞,还是会释放别人的锁;
- 要求判断锁和释放锁必须是原子化操作

- LUA脚本,解决判断锁和释放锁多条命令时的原子性的问题

- 编写脚本


- java实现lua脚本

- LUA获取锁

- LUA释放锁


以上还没有解决业务超时释放锁的问题,并且还有很多其他问题

分布式锁 Redisson 直接实现分布式锁;

- 引入Redisson


可重入锁
- 重入锁只针对「同一个线程多次获取同一把锁」的场景,和 "微服务" 没有直接关联。
- 只要是同一个线程、针对同一把分布式锁,无论执行多少个不同业务逻辑,都不需要 "抢锁"(不会被阻塞,能直接重入);但如果是不同的锁,依然需要正常竞争。

- 可重入锁原理



面试题
问题:Redisson 实现的分布式可重入锁,底层是如何保证 "可重入" 特性的?核心原理是什么?

问题:Redisson 分布式锁的 "看门狗(Watch Dog)" 机制是做什么的?核心执行逻辑是什么?为什么能解决锁超时释放的问题?

问题:Redisson 分布式锁在 Redis 主从集群 / 哨兵集群下,可能会出现 "锁丢失" 的问题,原因是什么?Redisson 提供了什么方案解决这个问题?

问题:Redisson 的分布式锁和 Java 原生的 ReentrantLock(可重入锁)有什么核心区别?从 "锁的作用范围、实现原理、适用场景" 三个维度对比说明。

问题:在使用 Redisson 分布式锁时,为什么必须保证lock()和unlock()成对出现?如果只调用lock()不调用unlock(),会有什么问题?如何避免这种问题?

