如何实现一个分布式锁?——来自 Java 老兵的实战总结 🚀🔐

如何实现一个分布式锁?------来自 Java 老兵的实战总结 🚀🔐

作者:写了 8 年 Java,踩了 8 年 Redis 的坑,终于把锁写顺的一位打工人

标签:#Java #分布式锁 #Redis #并发控制 #工具类封装


🧠 前言:为啥需要分布式锁?

很多人第一次听说"分布式锁"时会困惑:为啥不能用 synchronizedReentrantLock 呢?

因为它们只能保证单进程、多线程之间互斥 ,在分布式环境下(比如多个服务部署在不同机器),它们就失效了。

✅ 分布式锁的常见场景:

  • 防止重复下单(秒杀、抢购)
  • 限制库存扣减并发
  • 控制定时任务在集群中只执行一次
  • 保证接口幂等性

🔧 分布式锁常见实现方式

实现方式 优点 缺点
Redis 快速、轻量、适合短时锁 主从同步延迟可能导致锁失效
ZooKeeper CP模型,强一致性 实现复杂、性能略低
数据库 利用唯一索引或悲观锁 性能差、不适合高并发

今天我们重点讲解:基于 Redis 实现一个可复用的分布式锁工具类。


🚧 分布式锁的五大关键点

  1. 互斥性:同一时间只能有一个客户端获取锁
  2. 防死锁:锁必须设置过期时间
  3. 唯一标识:释放锁时必须验证是自己加的锁
  4. 原子性:加锁和设置过期时间必须是原子操作
  5. 高可用性:客户端必须具备重试机制

🛠️ 分布式锁工具类(基于 Redis)

我们使用的是最常见的单节点 Redis + Jedis 客户端实现(可替换为 RedissonLettuce)。

📦 Maven 依赖

xml 复制代码
<dependency>
  <groupId>redis.clients</groupId>
  <artifactId>jedis</artifactId>
  <version>4.4.3</version>
</dependency>

💡 RedisDistributedLock.java

typescript 复制代码
import redis.clients.jedis.Jedis;
import redis.clients.jedis.params.SetParams;

import java.util.UUID;

public class RedisDistributedLock {

    private final Jedis jedis;

    // 默认锁过期时间(毫秒)
    private static final int DEFAULT_EXPIRE_TIME = 10000;

    public RedisDistributedLock(Jedis jedis) {
        this.jedis = jedis;
    }

    /**
     * 获取锁
     * @param lockKey 锁的 key
     * @param requestId 请求标识(唯一性)
     * @param expireTime 锁过期时间(毫秒)
     * @return 是否成功获取锁
     */
    public boolean tryLock(String lockKey, String requestId, int expireTime) {
        SetParams params = new SetParams();
        params.nx().px(expireTime);
        String result = jedis.set(lockKey, requestId, params);
        return "OK".equals(result);
    }

    /**
     * 释放锁(必须验证是自己的锁)
     * @param lockKey 锁的 key
     * @param requestId 请求标识
     * @return 是否释放成功
     */
    public boolean releaseLock(String lockKey, String requestId) {
        String luaScript =
                "if redis.call('get', KEYS[1]) == ARGV[1] then " +
                        "return redis.call('del', KEYS[1]) " +
                "else return 0 end";

        Object result = jedis.eval(luaScript, 1, lockKey, requestId);
        return Long.valueOf(1).equals(result);
    }

    /**
     * 获取随机 requestId(UUID)
     */
    public String generateRequestId() {
        return UUID.randomUUID().toString();
    }
}

✅ 如何使用?Demo 来了!

🧪 DistributedLockDemo.java

csharp 复制代码
import redis.clients.jedis.Jedis;

public class DistributedLockDemo {

    public static void main(String[] args) {

        Jedis jedis = new Jedis("localhost", 6379);
        RedisDistributedLock lock = new RedisDistributedLock(jedis);

        String lockKey = "lock:order:123456";
        String requestId = lock.generateRequestId();

        try {
            boolean acquired = lock.tryLock(lockKey, requestId, 5000);
            if (acquired) {
                System.out.println("获取锁成功,开始执行业务逻辑");

                // 模拟业务处理
                Thread.sleep(3000);

                System.out.println("业务处理完成,准备释放锁");
            } else {
                System.out.println("获取锁失败,稍后重试");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            boolean released = lock.releaseLock(lockKey, requestId);
            if (released) {
                System.out.println("释放锁成功");
            } else {
                System.out.println("释放锁失败,可能不是当前线程持有");
            }
        }

        jedis.close();
    }
}

⚠️ 注意事项

  • requestId 必须唯一且线程安全,防止误删别人的锁
  • 必须设置过期时间,防止死锁
  • 释放锁必须原子操作,所以用了 Lua 脚本
  • 生产环境建议使用 Redisson,更健壮、支持 Watchdog

🚀 总结

分布式锁虽然听起来高大上,但本质就是**"在分布式环境下保证某段代码或资源的互斥访问"**。

你只需要记住:

分布式锁 = 加锁 + 可过期 + 可识别 + 可释放 + 可重试

通过封装成工具类,我们可以在任何业务场景中轻松使用,提升系统并发控制能力、避免竞态条件。


💬 最后

想要用 Java 写出靠谱的分布式系统,分布式锁你必须懂!

希望这篇文章能让你在面试和实战中都能自信回答:

"分布式锁?我自己写过一个!"

关注我,一起把 Java 写成架构图,写成 offer!🔥

相关推荐
小厂永远得不到的男人15 分钟前
基于 Spring Validation 实现全局参数校验异常处理
java·后端·架构
计算机编程小咖1 小时前
《基于大数据的农产品交易数据分析与可视化系统》选题不当,毕业答辩可能直接挂科
java·大数据·hadoop·python·数据挖掘·数据分析·spark
艾莉丝努力练剑1 小时前
【C语言16天强化训练】从基础入门到进阶:Day 7
java·c语言·学习·算法
老华带你飞1 小时前
校园交友|基于SprinBoot+vue的校园交友网站(源码+数据库+文档)
java·数据库·vue.js·spring boot·论文·毕设·校园交友网站
自强的小白2 小时前
学习Java24天
java·学习
Ashlee_code3 小时前
香港券商櫃台系統跨境金融研究
java·python·科技·金融·架构·系统架构·区块链
还梦呦3 小时前
2025年09月计算机二级Java选择题每日一练——第五期
java·开发语言·计算机二级
2501_924890523 小时前
商超场景徘徊识别误报率↓79%!陌讯多模态时序融合算法落地优化
java·大数据·人工智能·深度学习·算法·目标检测·计算机视觉
bobz9654 小时前
复姓人口比例不到 0.11%
面试
從南走到北4 小时前
JAVA国际版东郊到家同城按摩服务美容美发私教到店服务系统源码支持Android+IOS+H5
android·java·开发语言·ios·微信·微信小程序·小程序