有限资源的情况下,控制同一时间(段)只有某些线程(用户 / 服务器)能访问到资源。

Java 实现锁:synchronized 关键字、并发包的类

但存在问题:只对单个 JVM 有效

分布式锁

为什么需要分布式锁?

  1. 有限资源的情况下,控制同一时间(段)只有某些线程(用户 / 服务器)能访问到资源。
  2. 单个锁只对单个 JVM 有效

分布式锁实现的关键

抢锁机制

怎么保证同一时间只有 1 个服务器能抢到锁?

核心思想 就是:先来的人先把数据改成自己的标识(服务器 ip),后来的人发现标识已存在,就抢锁失败,继续等待。

等先来的人执行方法结束,把标识清空,其他的人继续抢锁。

MySQL 数据库:select for update 行级锁(最简单),或者用乐观锁。

Redis 实现:内存数据库,读写速度快。支持 setnx、lua 脚本,比较方便我们实现分布式锁。

setnx:set if not exists 如果不存在,则设置;只有设置成功才会返回 true,否则返回 false。

注意事项

1)用完锁要释放(腾地方)

2)锁一定要加过期时间

3)如果方法执行时间过长,锁提前过期了?

会导致问题:

  1. 连锁效应:释放掉别人的锁
  2. 这样还是会存在多个方法同时执行的情况

解决方案:续期

比如:

boolean end = false;

new Thread(() -> {
    if (!end)}{
    续期
})

end = true;

4)释放锁的时候,有可能先判断出是自己的锁,但这时锁过期了,最后还是释放了别人的锁

解决方案:Redis + lua 脚本保证操作原子性

// 原子操作
if(get lock == A) {
    // set lock B
    del lock
}

5)Redis 如果是集群(而不是只有一个 Redis),如果分布式锁的数据不同步怎么办?

解决方案:https://blog.csdn.net/feiying0canglang/article/details/113258494


项目分区导航:⬅️ 16-缓存 | 17-锁 | ➡️ 18-Java 后端万用项目模板介绍