SpringBoot 3.x中的的分布式锁与同步机制!

🏆本文收录于「滚雪球学SpringBoot」专栏(全网一个名),手把手带你零基础入门Spring Boot,从入门到就业,助你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
环境说明:Windows 10 + IntelliJ IDEA 2021.3.2 + Jdk 1.8
前言
💡 一句话概括: 分布式系统环境下,如何确保多个进程不会同时访问同一资源?Redis 和 ZooKeeper 是目前最常见的两种分布式锁方案,它们各有优缺点,今天我们就深入剖析它们的原理、实现方式以及最佳实践!
🌟 1. 前言:你是不是也被分布式系统的并发问题搞疯了?
在单机环境下,Java 的 synchronized 关键字 或 ReentrantLock 就能搞定多线程同步问题,然而在 分布式环境 里,事情可没那么简单!
场景想象:
假设你在运营一个电商平台,现在搞一个限时秒杀活动,5000 个用户同时冲进来抢购 100 台 iPhone,如果没有分布式锁,数据库可能会直接炸裂,订单数量可能远远超过库存!这就是典型的超卖问题!
于是,你开始寻找解决方案:
✅ 分布式锁,能保证同一时间只有一个服务实例能操作库存数据,其他请求要么等待,要么直接返回失败,从而避免超卖或数据混乱。
本篇文章将带你深入探讨 Redis 和 ZooKeeper 实现的分布式锁,并分析它们的优劣势,让你可以根据业务场景选择最合适的方案。
📖 2. 目录
- 🔐 分布式锁的概念与应用场景
- ⚡ 使用 Redis 实现分布式锁
- 🛠️ 基于 SETNX 的实现
- 🔄 可重入锁的改进
- 🚨 Redis 分布式锁的潜在问题
- 🏰 使用 ZooKeeper 实现分布式锁
- 🔄 解决分布式系统中的竞态条件与锁粒度
- 🛠️ 实战演练——用 Redis 和 ZooKeeper 解决秒杀超卖问题
- 🤔 总结与思考
🔐 3. 分布式锁的概念与应用场景
📌 3.1 什么是分布式锁?
分布式锁的核心目标是保证在分布式环境下,同一时间只有一个进程能访问某个资源。
在单机环境下,我们可以使用 Java 的 synchronized 或 ReentrantLock 来保证线程安全。但在分布式环境中,由于多个实例分布在不同的服务器上,必须使用一种可以跨多个节点协调的锁机制,这就是分布式锁。
🚀 3.2 典型应用场景
- 库存扣减(电商秒杀、商品限购)
- 任务调度(确保定时任务不会被多个实例同时执行)
- 订单去重(避免用户重复下单)
- 支付幂等(确保用户的支付请求不会被多次执行)
⚡ 4. 使用 Redis 实现分布式锁
Redis 是当前实现分布式锁最常见的方案之一,因其高性能、简单易用,被大量企业采用。
🛠️ 4.1 基于 SETNX 的实现
最基本的 Redis 分布式锁是使用 SETNX(Set if Not Exists)命令来实现的:
public boolean tryLock() {
long result = jedis.setnx("lock_key", "locked");
if (result == 1) {
jedis.expire("lock_key", 10); // 设置锁的过期时间,防止死锁
return true;
}
return false;
}
public void unlock() {
jedis.del("lock_key"); // 释放锁
}
⚠️ 问题:
- 如果锁的持有者崩溃,锁可能永远不会释放(死锁问题)!
SETNX不支持可重入锁!- 没有自动续期机制,导致锁可能在任务执行完成之前就被释放。
🔄 4.2 可重入锁的改进
可重入锁是指同一个线程可以多次获取同一把锁。为了解决 Redis 锁的可重入性,我们可以使用 UUID 作为锁的唯一标识:
private String lockValue = UUID.randomUUID().toString();
public boolean tryLock() {
String result = jedis.set("lock_key", lockValue, "NX", "EX", 10);
return "OK".equals(result);
}
public void unlock() {
if (lockValue.equals(jedis.get("lock_key"))) {
jedis.del("lock_key");
}
}
这样可以确保只有创建锁的进程才能释放锁,避免误删其他线程的锁。
🚨 4.3 Redis 分布式锁的潜在问题
| 问题 | 解决方案 |
|---|---|
| 锁超时被误删 | 采用 Redisson 进行自动续期 |
| 锁无法可重入 | 使用 UUID 作为锁标识 |
| 多进程竞争锁 | 采用 RedLock 算法提高可靠性 |
🏰 5. 使用 ZooKeeper 实现分布式锁
📝 5.1 基于临时顺序节点的实现
ZooKeeper 实现分布式锁的原理是创建 临时顺序节点,然后按照顺序来执行任务。
public void tryLock() throws KeeperException, InterruptedException {
String nodePath = zk.create("/lock_", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
List<String> children = zk.getChildren("/lock", false);
Collections.sort(children);
if (nodePath.equals("/lock/" + children.get(0))) {
System.out.println("获取锁成功:" + nodePath);
} else {
System.out.println("获取锁失败,等待中...");
}
}
🔍 5.2 ZooKeeper 分布式锁的优劣势
| 方案 | 优势 | 劣势 |
|---|---|---|
| Redis 分布式锁 | 高性能,适用于高并发 | 存在过期时间控制问题 |
| ZooKeeper 分布式锁 | 天然支持可重入锁 | 性能较低,依赖于 ZK 集群 |
🛠️ 6. 实战演练——用 Redis 和 ZooKeeper 解决秒杀超卖问题
场景: 我们要实现一个限量商品的秒杀功能,确保多个用户不会超卖商品库存。
public void seckill() {
if (redisLock.tryLock()) {
try {
// 扣减库存
} finally {
redisLock.unlock();
}
}
}
🤔 7. 总结与思考
- Redis 适用于高并发场景,但要注意锁超时问题。
- ZooKeeper 更稳定,但性能相对较低,适合强一致性需求的任务。
- Redisson 是 Redis 锁的增强版本,推荐使用。
- 分布式锁不是万能的,在设计系统时要综合考虑业务需求。
希望这篇文章能帮你搞懂分布式锁的实现!🚀
🧧福利赠与你🧧
无论你是计算机专业的学生,还是对编程有兴趣的小伙伴,都建议直接毫无顾忌的学习此专栏「滚雪球学SpringBoot」专栏(全网一个名),bug菌郑重承诺,凡是学习此专栏的同学,均能获取到所需的知识和技能,全网最快速入门SpringBoot,就像滚雪球一样,越滚越大, 无边无际,指数级提升。
最后,如果这篇文章对你有所帮助,帮忙给作者来个一键三连,关注、点赞、收藏,您的支持就是我坚持写作最大的动力。
同时欢迎大家关注公众号:「猿圈奇妙屋」 ,以便学习更多同类型的技术文章,免费白嫖最新BAT互联网公司面试题、4000G pdf电子书籍、简历模板、技术文章Markdown文档等海量资料。
✨️ Who am I?
我是bug菌(全网一个名),CSDN | 掘金 | InfoQ | 51CTO | 华为云 | 阿里云 | 腾讯云 等社区博客专家,C站博客之星Top30,华为云多年度十佳博主/价值贡献奖,掘金多年度人气作者Top40,掘金等各大社区平台签约作者,51CTO年度博主Top12,掘金/InfoQ/51CTO等社区优质创作者;全网粉丝合计 30w+;更多精彩福利点击这里;硬核微信公众号「猿圈奇妙屋」,欢迎你的加入!免费白嫖最新BAT互联网公司面试真题、4000G PDF电子书籍、简历模板等海量资料,你想要的我都有,关键是你不来拿。

-End-
- 点赞
- 收藏
- 关注作者
评论(0)