SpringBoot系列之基于Jedis实现分布式锁

本文详细介绍了在SpringBoot项目中如何利用Jedis实现分布式锁,从为何需要分布式锁、Redis分布式锁原理到具体的手动实现,包括设置过期时间和原子性操作,并讨论了可能出现的问题及解决方案,最后提供了测试和应用实例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Redis系列之基于Jedis实现分布式锁

1、为什么需要分布式锁

在单机环境,我们使用最多的是juc包里的单机锁,但是随着微服务分布式项目的普及,juc里的锁是不能控制分布锁环境的线程安全的,因为单机锁只能控制同个进程里的线程安全,不能控制多节点的线程安全,所以就需要使用分布式锁

2、redis分布式锁原理

学习之前先了解redis的命令,setnxexpire

  • setnx命令

    SETNX是SET if not exists的简写,设置key的值,如果key值不存在,则可以设置,否则不可以设置,这个有点像juc中cas锁的原理

    # setnx命令,相当于set和nx命令一起用
    setnx tkey aaa
    

    EX : 设置指定的到期时间(以秒为单位)。

    PX : 设置指定的到期时间(以毫秒为单

    NX : 仅在键不存在时设置键。

    XX : 只有在键已存在时才设置。

  • expire命令

如果只使用setnx不加上过期时间,手动释放锁时候出现异常,就会导致一直解不了锁,所以还是要加上ex

Spring Boot使用 Jedis 实现分布式锁是一种常见需求,尤其是在构建高并发、分布式系统时。Jedis 是一个轻量级的 Redis Java 客户端,支持直接与 Redis 交互。为了实现分布式锁,通常会利用 Redis 的 `SET key value NX PX milliseconds` 命令来保证锁的原子性和超时机制。 ### 使用 Jedis 实现分布式锁的基本步骤 1. **获取锁**:通过 `SET key value NX PX timeout` 命令尝试设置一个键值对,其中 `NX` 表示只有当键不存在时才设置成功,`PX` 表示设置过期时间(毫秒)。 2. **释放锁**:使用 Lua 脚本确保删除操作的原子性,避免误删其他客户端持有的锁。 以下是一个基于 Jedis 的简单实现示例: ```java import redis.clients.jedis.Jedis; import java.util.Collections; public class JedisDistributedLock { private final Jedis jedis; private final String lockKey; private final String lockValue; private final int expireTime; public JedisDistributedLock(Jedis jedis, String lockKey, String lockValue, int expireTime) { this.jedis = jedis; this.lockKey = lockKey; this.lockValue = lockValue; this.expireTime = expireTime; } public boolean acquireLock() { String result = jedis.set(lockKey, lockValue, "NX", "PX", expireTime); return "OK".equals(result); } public void releaseLock() { String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"; Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(lockValue)); if ("1".equals(result.toString())) { System.out.println("Lock released successfully."); } else { System.out.println("Failed to release lock."); } } } ``` ### 使用示例 ```java import redis.clients.jedis.Jedis; public class LockUsageExample { public static void main(String[] args) { try (Jedis jedis = new Jedis("localhost", 6379)) { String lockKey = "resource:lock"; String lockValue = "locked_by_thread_1"; int expireTime = 10000; // 10 seconds JedisDistributedLock lock = new JedisDistributedLock(jedis, lockKey, lockValue, expireTime); if (lock.acquireLock()) { try { // 执行业务逻辑 System.out.println("Lock acquired, executing business logic..."); Thread.sleep(5000); // 模拟业务处理时间 } catch (InterruptedException e) { Thread.currentThread().interrupt(); } finally { lock.releaseLock(); } } else { System.out.println("Failed to acquire lock."); } } } } ``` ### 注意事项 - **锁的可重入性**:上述实现不支持可重入,若需支持,需额外维护线程持有计数器。 - **锁续期**:对于长时间任务,应考虑引入看门狗机制自动延长锁的有效期[^3]。 - **Redis 单点问题**:为提高可靠性,建议使用 Redis Sentinel 或 Cluster 模式部署。 - **性能优化**:在高并发场景下,可以结合连接池如 JedisPool 提升性能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Nicky.Ma

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值