2026/6/20 11:30:04
网站建设
项目流程
广告设计与制作专业学什么课程,购物网站seo关键词定位,网站运行方案,福建企业网站建设引言
在分布式系统中#xff0c;多个服务实例往往需要同时访问同一共享资源#xff0c;例如#xff1a;
多节点同时修改同一条库存记录并发执行同一订单处理流程多实例定时任务同时触发并发写入同一个数据对象
如果没有分布式锁机制做互斥控制#xff0c;系统容易出现数据竞…引言在分布式系统中多个服务实例往往需要同时访问同一共享资源例如多节点同时修改同一条库存记录并发执行同一订单处理流程多实例定时任务同时触发并发写入同一个数据对象如果没有分布式锁机制做互斥控制系统容易出现数据竞争、写冲突、脏写、重复执行等问题。Redis 因为高性能、单线程执行模型、丰富的原子命令和 Lua 脚本支持成为当前最主流的分布式锁实现底座。而 Redisson 作为 Redis 官方推荐的 Java 客户端之一在锁语义、可重入性、自动续期、原子性保障等方面具有较高的工程完备度。本文将从工作原理到工程实践全面介绍 Redisson 分布式可重入锁RLock。一、为什么选择 Redisson 实现分布式锁如果直接手写 Redis 分布式锁例如使用SETNXEXPIRE会面临大量工程级问题问题原因典型风险SETNX 与 EXPIRE 非原子两条命令获取锁后未设置过期时间 → 死锁锁删除不安全业务线程崩溃 / 误删删除了别的线程的锁锁超时后自动释放EX 过期时间不足业务未执行完 → 锁提前过期导致数据错误不支持可重入SETNX 无法表达线程所有者同一线程再次加锁会造成自阻塞缺乏自动续期机制自己实现困难业务执行长任务容易导致锁失效Redisson 提供的 RLock 特性完整解决了上述问题可重入语义自动续期看门狗机制原子加锁 / 解锁Lua 脚本多种锁模式公平锁、联锁、红锁等分布式环境稳定可靠因此 Redisson 是 Java 体系中工程落地最完善的 Redis 分布式锁方案。二、Redisson 分布式锁底层原理1. 锁在 Redis 中的结构Redisson 使用 Redis 的Hash结构保存锁元数据Key: myLock Type: Hash Field: uuid:threadId Value: reentrant count Expire: 30 seconds (默认锁自动过期时间)示例HSET myLock e8c0d-...-12:23 1 EXPIRE myLock 30这带来几个重要特性支持可重入同一线程再次加锁只需增加次数不会阻塞线程级别锁所有权clientIdthreadId 作为唯一标识Redis TTL 控制过期防止死锁Hash 支持多个 field可扩展到联锁等高级场景2. 加锁流程详解加锁过程使用 Lua 脚本确保原子性核心流程简化逻辑锁不存在→ 设置 Hashfield当前线程并设置 TTL锁存在但属于当前线程→ 可重入次数1锁存在且不属于当前线程→ 阻塞等待或立即返回失败所有分支均由 Lua 脚本完成确保操作原子、不被打断。三、Spring Boot Redisson 配置示例ConfigurationpublicclassRedissonConfig{BeanpublicRedissonClientredissonClient(){ConfigconfignewConfig();config.useSingleServer().setAddress(redis://127.0.0.1:6379).setDatabase(0);returnRedisson.create(config);}}四、加锁与释放锁使用方法Redisson 提供两类常用加锁方式lock.lock()阻塞式加锁自动启动看门狗续期lock.tryLock(...)可设定等待时间与租期更灵活1. 使用 lock() —— 自动续期WatchdogServicepublicclassLockExampleService{AutowiredprivateRedissonClientredissonClient;publicvoidtestLock(){RLocklockredissonClient.getLock(order:lock);try{lock.lock();// 不指定时间 → 自动续期机制生效System.out.println(获取到锁执行操作...);Thread.sleep(60000);// 业务耗时看门狗续期保障锁有效}catch(Exceptione){e.printStackTrace();}finally{if(lock.isHeldByCurrentThread()){lock.unlock();}}}}特点默认锁过期时间30 秒自动续期看门狗每 10 秒刷新过期时间2. 使用 tryLock()publicvoidtryLockExample(){RLocklockredissonClient.getLock(product:lock);try{if(lock.tryLock(5,TimeUnit.SECONDS)){System.out.println(成功获取锁);Thread.sleep(30000);}else{System.out.println(未获取到锁);}}catch(Exceptione){e.printStackTrace();}finally{if(lock.isHeldByCurrentThread()){lock.unlock();}}}特点5 秒内阻塞等待拿到锁后启用看门狗自动续期五、看门狗Watchdog机制完整解析1. 看门狗的工作机制默认检查周期10 秒每次续期将锁 TTL 重置为 30 秒工作流程定时任务触发判断锁是否仍被当前线程持有若是 → 调用PEXPIRE myLock 30000若线程结束或锁已释放 → 停止续期2. 为什么需要续期如果业务耗时超过锁 TTL30s传统分布式锁会提前失效导致并发问题。续期确保业务执行再长也不会中途释放锁。3. 如何判断“锁属于当前线程”通过检查HEXISTS myLock clientId:threadId只要当前线程还是 lock 的 owner就继续续期。六、Redis 中锁的实时具象表现加锁后执行HGETALL order:lock TTL order:lock可能看到1) 7ab1e9...:23 2) 1 (integer) 30随着看门狗执行TTL 会保持波动但始终在 30 秒附近。七、锁释放原理Lua 脚本Redisson 使用 Lua 保证解锁的原子性。检查锁是否属于当前线程若重入次数 1 → 次数 -1若重入次数为 1 → 删除整个 key若锁不属于当前线程 → 不执行任何操作避免误删这个机制保证“只有锁持有者才能释放锁”。八、典型问题与常见误区FAQ1. 调用 lock.lock(10, TimeUnit.SECONDS) 会启用看门狗吗不会。指定租期时不启用看门狗锁达到指定时间后自动释放。2. 看门狗续期时间可以调整吗可以config.setLockWatchdogTimeout(45000);// 默认30s3. Redisson 如何避免死锁线程异常退出 → 看门狗停止续期默认 30s TTL 自动过期锁结构中包含线程标识避免误删4. 可重入锁意味着什么同一个线程可以多次获取该锁不会进入自阻塞lock.lock(); lock.lock(); // 重入计数15. 可否用于分布式事务可以用于分布式资源互斥但不能代替事务。十、完整业务案例库存扣减典型高并发场景ServicepublicclassStockService{AutowiredprivateRedissonClientredissonClient;publicvoiddeductStock(){RLocklockredissonClient.getLock(stock:lock);try{lock.lock();// 触发看门狗续期System.out.println(开始扣减库存...);// 模拟扣减操作Thread.sleep(30000);}catch(Exceptione){e.printStackTrace();}finally{if(lock.isHeldByCurrentThread()){lock.unlock();}}}}适用于秒杀减库存订单去重并发任务幂等控制分布式调度系统总结Redisson 是 Java 开发中最成熟的 Redis 分布式锁实现功能点Redisson 是否支持说明可重入分布式锁✔Hash 结构记录重入次数自动续期看门狗✔lock() 自动启用原子加锁与解锁✔Lua 脚本保障原子性死锁自动恢复✔TTL 到期自动释放公平锁、联锁、读写锁✔丰富的分布式同步结构高性能、可伸缩✔基于 Redis 单线程执行模型凭借其完善的锁语义、自动续期机制与 Lua 原子操作设计Redisson 是 Java 生态中分布式锁的首选方案适用于中大型业务中的强一致性场景。