当前位置: 首页 > news >正文

spring boot中使用RedissonClient实现分布式锁

spring boot中使用RedissonClient实现分布式锁

 1.参考文章:

https://developer.aliyun.com/article/952621

 

2.需要引入的依赖为:

<properties><redisson.version>3.20.1</redisson.version>
</properties><dependency><groupId>org.redisson</groupId><artifactId>redisson-spring-boot-starter</artifactId><version>${redisson.version}</version>
</dependency>

3.本地部署的redis为集群配置,所以在application.yml中添加配置:

spring:redis:cluster:nodes: 192.168.201.66:7001,192.168.201.66:7002,192.168.201.66:7003,192.168.201.66:7004,192.168.201.66:7005,192.168.201.66:7006password: csii@2021

4.RedisService实现分布式锁的实现类:

package com.csii.service;import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.concurrent.TimeUnit;/*** @description com.csii.service* @author: chengyu* @date: 2026-03-01 14:18*/
@Service
@Slf4j
public class RedisService {@Autowiredprivate RedissonClient redissonClient;/*** 获取锁* 如果锁不可用,则当前线程将无法参与线程调度,并处于休眠状态,直至获取该锁。* 实现注意事项 锁的实现可能能够检测到锁的错误使用,例如可能导致死锁的调用,并可能在这种情况下抛出(未检查的)异常。* 该锁实现必须记录这些情况和异常类型。*/public void lock(String lockKey) {try {RLock lock = redissonClient.getLock(lockKey);lock.lock();} catch (Exception e) {log.error("redis service lock error", e);throw e;}}/*** 尝试获取锁* 仅在调用时锁处于空闲状态时才获取该锁。* 如果锁可用,则获取该锁并立即返回true值。如果锁不可用,则此方法将立即返回false值。** @param lockKey* @return 返回值:若已获取锁,则返回true;否则返回false*/public boolean tryLock(String lockKey) {RLock lock = redissonClient.getLock(lockKey);return lock.tryLock();}/*** 尝试获取锁,给定一个等待时间* 如果在给定的等待时间内锁处于空闲状态,且当前线程未被中断,则获取该锁。** @param lockKey* @param waitTime 等待时间,单位s** @return 如果获取了锁,则返回值为true。 如果获取锁的过程中等待且指定的等待时间已过,则返回值为false*/public boolean tryLock(String lockKey, long waitTime) {try {RLock lock = redissonClient.getLock(lockKey);return lock.tryLock(waitTime, TimeUnit.SECONDS);} catch (Exception e) {log.error("redis service trylock error", e);}return false;}/*** 释放锁** @param lockKey* @return*/public boolean unlock(String lockKey) {RLock rLock = redissonClient.getLock(lockKey);if (rLock != null && rLock.isLocked()) {rLock.unlock();return true;}return false;}
}

5.测试redis分布式锁的Controller:

package com.csii.controller;import com.csii.service.RedisService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;/*** @description 测试redis分布式锁Controller* @author: chengyu* @date: 2026-03-01 14:50*/
@RestController
@Slf4j
public class TestLockController {@Autowiredprivate RedisService redisService;private static final String LOCK_KEY = "LOCK:EXECUTE:METHOD";@GetMapping("/testLock")public void callService() {Thread t1 = new Thread(() -> method2(), "thread1");Thread t2 = new Thread(() -> method2(), "thread2");Thread t3 = new Thread(() -> method2(), "thread3");t1.start();t2.start();t3.start();}/*** 尝试获取到锁才执行,给定一个等待获取锁的时间(2分钟)*/public void method2() {try {boolean acquire = redisService.tryLock(LOCK_KEY, 120);if (!acquire) {log.info("redis service try lock failed, method not execute and quit.");return;}log.info("method {} begin execute...", Thread.currentThread().getName());Thread.sleep(10000);log.info("method {} execute over", Thread.currentThread().getName());} catch (Exception e) {log.error(e.getMessage(), e);} finally {redisService.unlock(LOCK_KEY);}}/*** 获取到锁才执行*/public void method() {try {redisService.lock(LOCK_KEY);log.info("method {} begin execute...", Thread.currentThread().getName());Thread.sleep(20000);log.info("method {} execute over", Thread.currentThread().getName());} catch (Exception e) {log.error(e.getMessage(), e);} finally {redisService.unlock(LOCK_KEY);}}
}

6.查看执行结果:

2026-03-01 16:10:48.784  INFO 24120 --- [        thread1] com.csii.controller.TestLockController   : method thread1 begin execute...
2026-03-01 16:10:58.786  INFO 24120 --- [        thread1] com.csii.controller.TestLockController   : method thread1 execute over
2026-03-01 16:10:58.798  INFO 24120 --- [        thread2] com.csii.controller.TestLockController   : method thread2 begin execute...
2026-03-01 16:11:08.799  INFO 24120 --- [        thread2] com.csii.controller.TestLockController   : method thread2 execute over
2026-03-01 16:11:08.810  INFO 24120 --- [        thread3] com.csii.controller.TestLockController   : method thread3 begin execute...
2026-03-01 16:11:18.811  INFO 24120 --- [        thread3] com.csii.controller.TestLockController   : method thread3 execute over

可以看到是有序执行的。

因为方法的执行时间是10s,这里如果把获取锁的等待时间改为1s,则会报错,因为获取锁失败了:

查看代码
2026-03-01 16:12:36.951  INFO 24120 --- [        thread2] com.csii.controller.TestLockController   : method thread2 begin execute...
2026-03-01 16:12:37.946  INFO 24120 --- [        thread1] com.csii.controller.TestLockController   : redis service try lock failed, method not execute and quit.
2026-03-01 16:12:37.946  INFO 24120 --- [        thread3] com.csii.controller.TestLockController   : redis service try lock failed, method not execute and quit.
Exception in thread "thread3" Exception in thread "thread1" java.lang.IllegalMonitorStateException: attempt to unlock lock, not locked by current thread by node id: 2ba0d98b-a983-4fc0-9b0b-1d7feb4b6a29 thread-id: 463at org.redisson.RedissonBaseLock.lambda$unlockAsync0$6(RedissonBaseLock.java:369)at java.util.concurrent.CompletableFuture.uniHandle(CompletableFuture.java:822)at java.util.concurrent.CompletableFuture$UniHandle.tryFire(CompletableFuture.java:797)at java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:474)at java.util.concurrent.CompletableFuture.complete(CompletableFuture.java:1962)at org.redisson.command.CommandBatchService.lambda$executeAsync$7(CommandBatchService.java:301)at java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:760)at java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:736)at java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:474)at java.util.concurrent.CompletableFuture.complete(CompletableFuture.java:1962)at org.redisson.command.RedisCommonBatchExecutor.handleResult(RedisCommonBatchExecutor.java:163)at org.redisson.command.RedisExecutor.checkAttemptPromise(RedisExecutor.java:552)at org.redisson.command.RedisExecutor.lambda$execute$5(RedisExecutor.java:195)at java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:760)at java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:736)at java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:474)at java.util.concurrent.CompletableFuture.complete(CompletableFuture.java:1962)at org.redisson.client.handler.CommandDecoder.decodeCommandBatch(CommandDecoder.java:325)at org.redisson.client.handler.CommandDecoder.decodeCommand(CommandDecoder.java:217)at org.redisson.client.handler.CommandDecoder.decode(CommandDecoder.java:144)at org.redisson.client.handler.CommandDecoder.decode(CommandDecoder.java:120)at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:519)at io.netty.handler.codec.ReplayingDecoder.callDecode(ReplayingDecoder.java:366)at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:280)at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444)at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:440)at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166)at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:788)at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:724)at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:650)at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:562)at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997)at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)at java.lang.Thread.run(Thread.java:748)
java.lang.IllegalMonitorStateException: attempt to unlock lock, not locked by current thread by node id: 2ba0d98b-a983-4fc0-9b0b-1d7feb4b6a29 thread-id: 461at org.redisson.RedissonBaseLock.lambda$unlockAsync0$6(RedissonBaseLock.java:369)at java.util.concurrent.CompletableFuture.uniHandle(CompletableFuture.java:822)at java.util.concurrent.CompletableFuture$UniHandle.tryFire(CompletableFuture.java:797)at java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:474)at java.util.concurrent.CompletableFuture.complete(CompletableFuture.java:1962)at org.redisson.command.CommandBatchService.lambda$executeAsync$7(CommandBatchService.java:301)at java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:760)at java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:736)at java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:474)at java.util.concurrent.CompletableFuture.complete(CompletableFuture.java:1962)at org.redisson.command.RedisCommonBatchExecutor.handleResult(RedisCommonBatchExecutor.java:163)at org.redisson.command.RedisExecutor.checkAttemptPromise(RedisExecutor.java:552)at org.redisson.command.RedisExecutor.lambda$execute$5(RedisExecutor.java:195)at java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:760)at java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:736)at java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:474)at java.util.concurrent.CompletableFuture.complete(CompletableFuture.java:1962)at org.redisson.client.handler.CommandDecoder.decodeCommandBatch(CommandDecoder.java:325)at org.redisson.client.handler.CommandDecoder.decodeCommand(CommandDecoder.java:217)at org.redisson.client.handler.CommandDecoder.decode(CommandDecoder.java:144)at org.redisson.client.handler.CommandDecoder.decode(CommandDecoder.java:120)at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:519)at io.netty.handler.codec.ReplayingDecoder.callDecode(ReplayingDecoder.java:366)at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:280)at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444)at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:440)at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166)at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:788)at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:724)at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:650)at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:562)at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997)at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)at java.lang.Thread.run(Thread.java:748)
2026-03-01 16:12:46.953  INFO 24120 --- [        thread2] com.csii.controller.TestLockController   : method thread2 execute over

 

http://www.jsqmd.com/news/424735/

相关文章:

  • 2026 年 3 月 GEO 优化服务商综合评选:TOP10 实力排名与选型攻略 - 速递信息
  • 《R语言医学数据分析实战》学习记录|第五章 基本统计分析
  • git pull中ssh key设置
  • Ajax
  • 解密synchronized:从对象头到内存屏障,搞懂Java锁的底层原理
  • 效率直接起飞! 降AI率平台 千笔·专业降AIGC智能体 VS 灵感ai,本科生专属选择
  • 2026 GEO 服务商 TOP10 实力榜单:企业长期合作优选名单 - 速递信息
  • 【MySQL|进阶】存储过程
  • 救命神器!自考人必备的AI论文网站 —— 千笔·专业学术智能体
  • 2026年大棚棉被工厂推荐,专注大棚保温被多年生产经验 - 品牌鉴赏师
  • 2026 年 3 月 GEO 服务商权威榜单|TOP5 实力对比与企业选型指南 - 速递信息
  • 实测才敢推AI论文写作软件 千笔·专业学术智能体 VS 笔捷Ai 本科生必备
  • 2026 年 3 月 GEO 服务商深度盘点:TOP5 哪家更适合企业长期合作? - 速递信息
  • 研究生必看!人气爆表的AI论文网站 —— 千笔AI
  • 2026别错过!AI论文工具 千笔AI VS 万方智搜AI,MBA写论文神器!
  • 2026年双梁门式起重机好用的品牌排名,靠谱厂家推荐 - 工业品网
  • GEO 驱动增长:上海智推时代官方合作通道直达 - 速递信息
  • 2026年蚌埠护理专业学校怎么选择,权威院校全梳理 - 工业设备
  • 实测才敢推!8个降AI率软件降AIGC网站:专科生必看的降AI率工具测评与推荐
  • 聊聊2026年河南好用的全包家装公司,郑州派轩装修公司口碑出众 - myqiye
  • 论文写不动?AI论文写作软件 千笔写作工具 VS 灵感ai
  • 新疆酒店设计装修服务多少钱,有哪些好用的品牌推荐? - mypinpai
  • 2026寻找性价比高的温度记录仪品牌适合电子行业的有哪些 - 工业品牌热点
  • 2026生物饲料水分测定仪供应商推荐,满足不同需求 - 工业品网
  • 母线槽产品类型研究分析报告 - 速递信息
  • 聊聊合肥电子商务学校服务有哪些,哪家权威值得关注 - 工业设备
  • 分析2026年靠谱的电源管理芯片厂家,价格如何 - 工业推荐榜
  • 2026年河南售后完善的家装品牌企业推荐,帮我找靠谱家装公司 - myqiye
  • 我做了个 Codex 账号切换器:终于不用担心token用量了
  • 2026年度新疆酒店设计服务推荐,新疆匠之初装饰设计专业靠谱 - mypinpai