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

Redis分布式锁简单实现

什么是分布式锁?

像synchronized、ReentrantLock这些都是Jvm锁,可以确保在单个jvm中,多线程访问共享资源安全性,当多个线程访问共享资源的时候,用 synchronized、ReentrantLock 将共享资源包裹起来,可确保共享资源只能被串行访问。

Redis分布式锁实现

1. 引入redisson配置

<!-- redisson -->
<dependency><groupId>org.redisson</groupId><artifactId>redisson-spring-boot-starter</artifactId><version>3.20.1</version>
</dependency>

2. RedissonConfig

yaml配置

spring:redis:host: 127.0.0.1port: 6379
@Configuration
public class RedissonConfig {@Autowiredprivate RedisProperties redisProperties;@Beanpublic RedissonClient redissonClient() {Config config = new Config();config.useSingleServer().setAddress("redis://" + redisProperties.getHost() + ":" + redisProperties.getPort()).setPassword(redisProperties.getPassword()).setDatabase(redisProperties.getDatabase());return Redisson.create(config);}
}

3. 接口实现类

/*** 分布式锁工具类*/
public interface DistributeLock {/*** 尝试获取分布式锁,获取到锁后执行 supplier.get() 方法,然后释放锁,返回执行的返回值;若无法获取锁,抛出异常* 获取锁的过程不会阻塞* 锁会自动续期** @param lockKey  上锁的key* @param supplier 需要执行的业务* @return 执行的返回值*/<T>  T tryLockRun(String lockKey, Supplier<T> supplier);/*** 尝试在指定的时间内获取分布式锁,获取到锁后执行 supplier.get() 方法,然后释放锁,返回执行的返回值;若无法获取锁,抛出异常;此方法最多阻塞时长由waitTime指定* 获取锁的过程会阻塞,阻塞时长由 waitTime 指定* 锁会自动续期** @param lockKey  上锁的key* @param supplier 需要执行的业务* @param waitTime 获取锁等待时间,必须大于 0* @param unit     时间单位* @return 执行的返回值*/<T>  T tryLockRun(String lockKey, Supplier<T> supplier, long waitTime, TimeUnit unit);/*** 尝试在指定的时间内获取分布式锁,获取到锁后执行 supplier.get() 方法,然后释放锁,返回执行的返回值;若无法获取锁,抛出异常;此方法最多阻塞时长由waitTime指定* 获取锁的过程会阻塞,阻塞时长由 waitTime 指定* 超过了 leaseTime,若锁还未释放,则自动释放** @param lockKey   上锁的key* @param supplier  需要执行的业务* @param waitTime  获取锁等待时间,必须大于 0* @param leaseTime 锁持有时间(必须大于 0:超过了这个时间,若未主动释放,则会自动释放)* @param unit      时间单位* @return 执行的返回值*/<T>  T tryLockRun(String lockKey, Supplier<T> supplier, long waitTime, long leaseTime, TimeUnit unit) ;/*** 此方法会一直等待,直到获取锁后,获取到锁后执行  supplier.get() 方法,然后释放锁* 获取锁的过程会阻塞,直到成功获取锁* 锁会自动续期** @param lockKey  上锁的key* @param supplier 需要执行的业务* @return 执行的返回值*/<T>  T lockRun(String lockKey, Supplier<T> supplier);/*** 此方法会一直等待,直到获取锁后,获取到锁后执行  supplier.get() 方法,然后释放锁* 获取锁的过程会阻塞,直到成功获取锁* 超过了 leaseTime,若锁还未释放,则自动释放** @param lockKey   上锁的key* @param supplier  需要执行的业务* @param leaseTime 锁持有时间(必须大于 0:超过了这个时间,若未主动释放,则会自动释放)* @param unit      时间单位* @return 执行的返回值      */<T>  T lockRun(String lockKey, Supplier<T> supplier, long leaseTime, TimeUnit unit);
}

@Service
@Slf4j
@RequiredArgsConstructor
public class DistributeLockImpl implements DistributeLock {private final RedissonClient redissonClient;// 锁前缀--可以加载配置里用来区分不同的业务private static final String LOCK_KEY_PREFIX = "lock:";@Overridepublic <T> T tryLockRun(String lockKey, Supplier<T> supplier) {Objects.requireNonNull( supplier, "Supplier cannot be null");Objects.requireNonNull(lockKey, "Lock key cannot be null");String redisKey = LOCK_KEY_PREFIX+lockKey;RLock lock = redissonClient.getLock(redisKey);boolean  flag = lock.tryLock();if (!flag) {throw new RuntimeException("获取锁失败,锁被占用");}try {//执行锁内逻辑代码return supplier.get();} finally {lock.unlock();}}@Overridepublic <T> T tryLockRun(String lockKey, Supplier<T> supplier, long waitTime, TimeUnit unit) {Objects.requireNonNull( supplier, "Supplier cannot be null");Objects.requireNonNull(lockKey, "Lock key cannot be null");if (waitTime < 0){throw new IllegalArgumentException("Wait time should ge 0");}String redisKey = LOCK_KEY_PREFIX+lockKey;RLock lock = redissonClient.getLock(redisKey);try {boolean  flag = lock.tryLock(waitTime,unit);if (!flag) {throw new RuntimeException("获取锁失败,锁被占用");}//执行锁内逻辑代码return supplier.get();} catch (Exception e){throw new RuntimeException("获取锁异常->{}",e);} finally {lock.unlock();}}@Overridepublic <T> T tryLockRun(String lockKey, Supplier<T> supplier, long waitTime, long leaseTime, TimeUnit unit)  {Objects.requireNonNull( supplier, "Supplier cannot be null");Objects.requireNonNull(lockKey, "Lock key cannot be null");if (waitTime < 0){throw new IllegalArgumentException("Wait time should ge 0");}if (leaseTime < 0){throw new IllegalArgumentException("Lease time should ge 0");}String redisKey = LOCK_KEY_PREFIX+lockKey;RLock lock = redissonClient.getLock(redisKey);try {boolean  flag = lock.tryLock(waitTime,leaseTime,unit);if (!flag) {throw new RuntimeException("获取锁失败,锁被占用");}//执行锁内逻辑代码return supplier.get();} catch (Exception e){throw new RuntimeException("获取锁异常->{}",e);} finally {lock.unlock();}}@Overridepublic <T> T lockRun(String lockKey, Supplier<T> supplier) {Objects.requireNonNull( supplier, "Supplier cannot be null");Objects.requireNonNull(lockKey, "Lock key cannot be null");String redisKey = LOCK_KEY_PREFIX+lockKey;RLock lock = redissonClient.getLock(redisKey);lock.lock();try {//执行锁内逻辑代码return supplier.get();} finally {lock.unlock();}}@Overridepublic <T> T lockRun(String lockKey, Supplier<T> supplier, long leaseTime, TimeUnit unit) {Objects.requireNonNull( supplier, "Supplier cannot be null");Objects.requireNonNull(lockKey, "Lock key cannot be null");if (leaseTime < 0){throw new IllegalArgumentException("Lease time should ge 0");}String redisKey = LOCK_KEY_PREFIX+lockKey;RLock lock = redissonClient.getLock(redisKey);lock.lock(leaseTime,unit);try {//执行锁内逻辑代码return supplier.get();} catch (Exception e){throw new RuntimeException("获取锁异常->{}",e);} finally {lock.unlock();}}
}

4. 使用方法

 this.distributeLock.lockRun("lock1", () -> {//执行业务逻辑 retren null;});

测试类

1. 测试1

@GetMapping("/tryLockRun")
public String tryLockRun() {long startTime = System.currentTimeMillis();boolean lockResult = this.distributeLock.tryLockRun("lock1", () -> {log.info("获取锁成功,执行业务");try {TimeUnit.SECONDS.sleep(5);} catch (InterruptedException e) {throw new RuntimeException(e);}return true;});log.info("耗时:{},{}", (System.currentTimeMillis() - startTime), lockResult ? "获取锁成功" : "获取锁失败");return lockResult ? "获取锁成功" : "获取锁失败";
}

第一次调用获取到锁,执行任务,其它线程抢占报错

2. 测试2

@GetMapping("/tryLockRunWaitTime")
public String tryLockRunWaitTime() {long startTime = System.currentTimeMillis();log.info("tryLockRunWaitTime start");boolean lockResult = this.distributeLock.tryLockRun("lock1", () -> {log.info("获取锁成功,执行业务");try {TimeUnit.SECONDS.sleep(5);} catch (InterruptedException e) {throw new RuntimeException(e);}return true;}, 4, TimeUnit.SECONDS);log.info("耗时:{},{}", (System.currentTimeMillis() - startTime), lockResult ? "获取锁成功" : "获取锁失败");return lockResult ? "获取锁成功" : "获取锁失败";
}

3. 测试3

 @GetMapping("/lockRun")public String lockRun() {long startTime = System.currentTimeMillis();log.info("lockRun start");this.distributeLock.lockRun("lock1", () -> {log.info("获取锁成功,执行业务");try {TimeUnit.SECONDS.sleep(5);} catch (InterruptedException e) {throw new RuntimeException(e);}return true;});log.info("获取锁成功,耗时:{}", (System.currentTimeMillis() - startTime));return "获取锁成功";}

http://www.dtcms.com/a/315153.html

相关文章:

  • 安卓的NDK、ABI、JNI到底是指啥?区别与联系是?
  • Prometheus-3--Prometheus是怎么抓取Java应用,Redis中间件,服务器环境的指标的?
  • Ollama入门实战
  • ES集群规划与调优
  • Matlab(1)
  • 蓝桥杯----AT24C02
  • 【Git】怎么将https://coding.net的仓库迁移至https://cnb.cool/
  • 拉格朗日松弛算法求解VRP(Vehicle Routing Problem)车辆路径问题和简单示例
  • Linux的进程管理与监控和任务工具crontab的使用
  • 臭氧、颗粒物和雾霾天气过程的大气污染物计算 CAMx模型
  • 用思维框架拆解知识,开启高效学习之旅
  • 【基础完全搜索】USACO Bronze 2019 January - 猜动物Guess the Animal
  • RabbitMQ--介绍
  • 498. 对角线遍历
  • JUCE VST AI 开源
  • 2025最好的Dify入门到精通教程(上)
  • 微服务的编程测评系统10-竞赛删除发布-用户管理-登录注册
  • 县级融媒体中心备份与恢复策略(精简版3-2-1架构)
  • 【网络安全】不安全的反序列化漏洞
  • P1550 [USACO08OCT] Watering Hole G
  • 【达梦MPP(带主备)集群搭建】
  • python包管理器uv踩坑
  • Golang中的`io.Copy()`使用场景
  • Java 的 APT(Annotation Processing Tool)机制详解
  • 【MyBatis-Plus笔记】MyBatis-Plus详解
  • JuiceFS on Windows: 首个 Beta 版的探索与优化之路
  • 【多智能体cooragent】CoorAgent 系统中 5 个核心系统组件分析
  • 【笔记】ROS1|3 Turtlebot3汉堡Burger建SLAM地图并导航【旧文转载】
  • 数学 理论
  • 基于FAISS和Ollama的法律智能对话系统开发实录-【大模型应用班-第5课 RAG技术与应用学习笔记】