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

Redis的分布式锁及其实现Redisson

前言

分布式锁是控制分布式系统之间同步访问共享资源的一种方式。
在分布式系统中,常常需要协调他们的动作。如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要互斥来防止彼此干扰来保证一致性,这个时候,便需要使用到分布式锁。

什么是分布式锁

1.在分布式环境中使用到的锁就是分布式锁
2.在分布式环境中对不同应用程序操作的共享资源进行加锁就是分布式锁

分布式环境

1.同一个应用下的子应用采用单独部署的方式运行就是分布式
2.只要应用存在跨JVM就是分布式环境

为什么要有分布式锁

JDK中原生锁(Synchronized、Lock)只针对是同一个JVM实例上操作资源而言,对于不同JVM的操作是没办法进行加锁的。

分布式锁的应用场景

只要存在跨JVM操作,并且存在共享资源竞争问题,就是必须使用到分布式锁的场景。

分布式锁有哪些

常见的分布式锁有以下几种:
1.基于数据库(乐观锁)实现分布式锁
2.基于Redis的分布式锁Redisson
3.基于Zookeeper实现分布式锁

基于redis分布式锁原理

获取锁

通过Redis创建一个唯一的key,如果当前线程能创建这个唯一的key,则表示当前线程获取到锁。

释放锁

当删除Redis中的代表锁的唯一key,则表示释放锁。

什么是死锁

在释放锁时出现异常,Redis中代表锁的唯一key未被删除,而其他线程一直在自旋等待并希望能够获取锁,但事实上所有线程都没能获取到锁的情况称为死锁。

如何解决死锁

我们可以通过对Redis中代表锁的唯一Key设置过期时间来避免死锁的发生。

如何避免锁被其他线程释放

创建锁时记录线程ID,自己的锁只能自己释放。

如何保证锁的可重入性

当线程获取到锁后在Redis中把当前线程的ID做为key的值进行存储,加锁时判断当前线程与Redis锁的值是否一致。

基于redis分布式锁Redisson

配置pom.xml

<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>site.yangpan</groupId> <artifactId>yangpan-spring-boot</artifactId> <version>0.0.1-SNAPSHOT</version> </parent> <groupId>site.yangpan.redission</groupId> <artifactId>yangpan-spring-boot-redission</artifactId> <version>0.0.1-SNAPSHOT</version> <name>yangpan-spring-boot-redission</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--下面这两个依赖就是集成redission的依赖--> <!--第一个依赖与spring boot版本有关系,参考官方文档--> <dependency> <groupId>org.redisson</groupId> <artifactId>redisson-spring-data-21</artifactId> <version>3.13.3</version> </dependency> <dependency> <groupId>org.redisson</groupId> <artifactId>redisson-spring-boot-starter</artifactId> <version>3.13.3</version> </dependency> </dependencies> </project>

注意:网上很多都是直接引入redission依赖,但是我这里是通过Spring Boot Starter的方式引入

配置application.properties

# 公共spring boot配置 spring.redis.host=127.0.0.1 spring.redis.port=6379 spring.redis.password= #spring.redis.cluster.nodes= #spring.redis.sentinel.master= #spring.redis.sentinel.nodes= ## Redisson 配置 spring.redis.redisson.config=classpath:redisson.yaml

配置redisson.yaml

singleServerConfig: idleConnectionTimeout: 10000 pingTimeout: 1000 # connectTimeout: 10000 timeout: 3000 retryAttempts: 3 retryInterval: 1500 # reconnectionTimeout: 3000 # failedAttempts: 3 password: subscriptionsPerConnection: 5 clientName: address: "redis://127.0.0.1:6379" subscriptionConnectionMinimumIdleSize: 1 subscriptionConnectionPoolSize: 50 connectionMinimumIdleSize: 32 connectionPoolSize: 64 database: 0 # dnsMonitoring: false dnsMonitoringInterval: 5000 threads: 0 nettyThreads: 0 codec: !<org.redisson.codec.JsonJacksonCodec> {} #"transportMode":"NIO"

编写RedissonSpringDataConfig

接下来我们注册 RedissonConnectionFactory 到 Spring context

package site.yangpan.redission.config; import org.redisson.Redisson; import org.redisson.api.RedissonClient; import org.redisson.config.Config; import org.redisson.spring.data.connection.RedissonConnectionFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.Resource; import java.io.IOException; /** * 注册 RedissonConnectionFactory 到 Spring context * https://github.com/redisson/redisson/tree/master/redisson-spring-data#spring-data-redis-integration * Created by yangpan on 2020-08-29 19:15. */ @Configuration public class RedissonSpringDataConfig { @Bean public RedissonConnectionFactory redissonConnectionFactory(RedissonClient redisson) { return new RedissonConnectionFactory(redisson); } @Bean(destroyMethod = "shutdown") public RedissonClient redisson(@Value("classpath:/redisson.yaml") Resource configFile) throws IOException { Config config = Config.fromYAML(configFile.getInputStream()); return Redisson.create(config); } }

使用Redisson

这里我们直接编写一个controller,然后使用Redisson

package site.yangpan.redission.reentrantLock; import org.redisson.api.RLock; import org.redisson.api.RedissonClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * 基于Redis的Redisson分布式可重入锁RLock * Java对象实现了java.util.concurrent.locks.Lock接口。 * 同时还提供了异步(Async)、反射式(Reactive)和RxJava2标准的接口。 * Created by yangpan on 2020-08-29 19:40. */ @Controller @RestController @RequestMapping("/redissionReentrantLock") public class RedissonReentrantLock { private Integer stock = 100; @Autowired private RedissonClient redissonClient; @GetMapping("/test") public void test(){ //使用线程池模拟并发,看分布式锁有没有问题 ExecutorService executorService = Executors.newFixedThreadPool(8); for(int i=0;i<=1000;i++){ executorService.execute(() -> { try { Thread.sleep(3000); //调用加锁方法 reduceStockRessionLock(); } catch (InterruptedException e) { e.printStackTrace(); } }); } } /** * 加锁情况 */ private void reduceStockRessionLock() { //获取锁(可重入锁) RLock lock = redissonClient.getLock("anyLock"); //加锁 lock.lock(); //业务操作 if(stock > 0){ stock--; System.out.println("当前库存剩余:" + stock); } //释放锁 lock.unlock(); } /** * 不加锁情况 */ private void reduceStock() throws InterruptedException { //业务操作 if(stock > 0){ stock--; System.out.println("当前库存剩余:" + stock); } } }

启动测试

接下来我们启动项目,访问接口,查看日志,观察日志分析可得Redisson分布式锁确实起到了作用

curl http://localhost:8080/redissionReentrantLock/test
http://www.jsqmd.com/news/587766/

相关文章:

  • 高性能缓存架构
  • SecGPT-14B开发者案例:将模型API嵌入内部安全知识库与工单系统
  • 基于web实验——JSP环境搭建
  • 基于vue3与pinia构建电商核心模块,快马平台实战演练购物车与商品列表
  • 效率翻倍:基于快马AI定制你的专属高效git配置工作流
  • 新手必看:在快马平台用github学生认证完成首个项目
  • 终极解决方案:3种简单方法彻底解决Dify工作流中的图片显示问题
  • 智能化磁盘空间革命:CleanMyWechat如何一键释放微信PC端数十GB存储空间
  • 4.2软考高项-每日5题
  • 蓝桥杯算法精讲:二分算法之二分答案深度剖析
  • 号易官方邀请码是多少?邀请码666666 独特地位与优势全解析 - 号易-号易官网招商
  • AI学习笔记二
  • PE结构 --->8.PE对齐的概念 文件对齐VS磁盘对齐
  • task jitter计算方法
  • 告别繁琐安装:用快马平台在线环境,三步创建你的第一个网页应用
  • 【ESP32-S3 深度实战】从小智AI底层移植到自定义LVGL表情:M5Stack CoreS3 避坑与架构指南
  • 硬件笔记——立创逻辑派开关电源案例解读
  • 零基础学Java:用快马AI生成你的第一个集合与对象管理程序
  • 提升开发效率:用快马一键生成智能排序工具模块
  • PE结构 ---> 9.RvaToFoa 内存状体到文件状态
  • 如何用PHP实现线程安全的单例模式?
  • 《黄金周人山人海,节后门可罗雀——景区怎么把这个差距缩小?》
  • 3种突破:ctfileGet如何解除城通网盘限速枷锁
  • 快马平台快速构建mysql博客系统原型:十分钟搞定数据库与api
  • Oracle EBS 资产类别是 真正的树形层级结构(通过弹性域实现父子关系),而 SAP 资产类别(Asset Class)是 扁平结构(无系统内置层级)
  • 飞牛openclaw使用指南(免费模型,不消耗token,响应快,无qps限制,无限使用!!)
  • 实战指南:基于快马生成openclaw千问的智能文档问答系统完整项目
  • 番茄小说下载器:3分钟搭建你的个人离线图书馆完整指南
  • 面试“逆袭率”第一的秘密:让我为你细细阐述
  • Oracle EBS和SAP在资产类别层级关系上的差异