--- title: "17-锁" created: 2025-12-02 tags: - 项目 aliases: - 锁 --- # 锁 ## 锁 有限资源的情况下,控制同一时间(段)只有某些线程(用户 / 服务器)能访问到资源。 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. 这样还是会存在多个方法同时执行的情况 解决方案:续期 比如: ```java boolean end = false; new Thread(() -> { if (!end)}{ 续期 }) end = true; ``` 4)释放锁的时候,有可能先判断出是自己的锁,但这时锁过期了,最后还是释放了别人的锁 解决方案:Redis + lua 脚本保证操作原子性 ```java // 原子操作 if(get lock == A) { // set lock B del lock } ``` 5)Redis 如果是集群(而不是只有一个 Redis),如果分布式锁的数据不同步怎么办? 解决方案: --- **项目分区导航**:⬅️ [[16-缓存|16-缓存]] | 17-锁 | ➡️ [[18-Java 后端万用项目模板介绍|18-Java 后端万用项目模板介绍]]