Redisson-分布式锁单Redis节点模式

Redisson-分布式锁单Redis节点模式

为什么要用分布式锁?

使用分布式锁的主要目的是为了解决多线程或多进程并发访问共享资源时可能出现的竞争条件和数据一致性问题。举一些实际场㬌:

  1. 数据库并发控制:在分布式系统中,多个节点同时操作数据库时,可能会导致数据不一致或冲突。通过使用分布式锁,可以确保同一时间只有一个节点能够对特定数据进行修改,从而避免出现脏读、幻读等问题。
  2. 资源限制和瓶颈控制:某些资源(如文件、接口调用次数等)需要限制同时访问的数量,在高并发环境下通过使用分布式锁可以有效地控制资源的访问数量。
  3. 防止死锁:在复杂系统中,由于各种原因(如网络故障、程序错误等),可能导致死锁情况。通过使用带有超时机制的分布式锁,可以防止因为单个节点故障而导致整个系统陷入死锁状态。

使用分布式锁能够保证共享资源被安全地访问和修改,并且能够提供良好的并发性能和可靠性。

目前的市场使用的分布式锁有哪些?(个人了解不代表所有)

  1. 基于数据库的分布式锁
    优点:简单易实现,使用现有的数据库即可,不需要额外的基础设施。
    缺点:性能相对较低,数据库的I/O操作开销大,还需要处理数据库的死锁问题。

  2. 基于Redis的分布式锁
    优点:高性能,Redis是内存数据库,读写速度快,Redis支持多种数据结构,灵活性高。
    缺点:需要确保Redis集群的高可用性和一致性,否则可能导致锁的失效。

  3. 基于Redisson的分布式锁
    优点: 内置多种锁的实现,适用于不同场景,提高了锁的可靠性。
    缺点:封装了很多功能,引入了一些额外的开销,相对直接使用Redis的命令,增加了项目依赖。

  4. 基于Zookeeper的分布式锁
    优点:实现分布式锁的过程中能够自动处理网络分区和节点故障,支持临时节点,可以自动释放锁。
    缺点:实现较为复杂!!!性能相对Redis较低,因为Zookeeper需要维护强一致性。

使用Redisson实现分布式锁

我用的是Spring Boot 的框架,没有什么心思写文章就直接写代码吧~

demo包类结构
在这里插入图片描述
pom.xml

<dependencies><!--  redis缓存  --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><!-- Redisson分布式锁   --><dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>3.12.0</version></dependency></dependencies>

yml配置

server:port: 8081servlet:context-path: /api
spring:redis:host: 服务器ipport: 6379
#    password: 123456timeout: 60000database: 5

配置类

package com.springboot.redisson.config;import lombok.Data;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.redisson.config.SingleServerConfig;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;@Data
@Configuration
@ConfigurationProperties("spring.redis")
public class RedissonConfig {private String host;private String password;private String port;private int timeout = 3000;private int connectionPoolSize = 64;private int connectionMinimumIdleSize=10;private int pingConnectionInterval = 60000;private static String ADDRESS_PREFIX = "redis://";/*** 自动装配**/@BeanRedissonClient redissonSingle() {Config config = new Config();//  判断redis 的host是否为空if(StringUtils.isEmpty(host)){throw new RuntimeException("host is  empty");}//  配置host,port等参数SingleServerConfig serverConfig = config.useSingleServer()// 节点地址.setAddress(ADDRESS_PREFIX + this.host + ":" + port)// 命令等待超时,单位:毫秒.setTimeout(this.timeout).setPingConnectionInterval(pingConnectionInterval)// 连接池大小.setConnectionPoolSize(this.connectionPoolSize)// 最小空闲连接数.setConnectionMinimumIdleSize(this.connectionMinimumIdleSize);//  判断进入redis 是否密码if(!StringUtils.isEmpty(this.password)) {serverConfig.setPassword(this.password);}return Redisson.create(config);}
}

controller

package com.springboot.redisson.controller;import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RCountDownLatch;
import org.redisson.api.RLock;
import org.redisson.api.RReadWriteLock;
import org.redisson.api.RedissonClient;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;
import java.util.UUID;
import java.util.concurrent.TimeUnit;@Slf4j
@RestController
@RequestMapping("redisson")
public class RedissonController {@ResourceRedissonClient redissonSingle;@ResourceRedisTemplate<String,Object> redisTemplate;@GetMapping("/")private String TestString(){return "Hello redisson!";}/*** RLock lock = redissonSingle.getLock("my-redisson-lock");* lock.lock();* 使用的是可重入锁*  可重入锁: 可重入锁是一个分布式锁,它可以用于多个线程访问同一把锁的等待保证数据的唯一性*      例如: 当有一个线程在访问一个可重入锁的时候,就会自动加锁,其它线程再次访问同一把锁有时候只能等待,*              当线程释放锁的时候,其它线程才可以访问,每次只能有一个线程进行访问,* @return*/@GetMapping("no1")public String TestRedisson01(){RLock lock = redissonSingle.getLock("my-redisson-lock");lock.lock();try {log.info("NO1加锁成功,正在处理业务逻辑》》》》》");System.out.println("好长的业务");Thread.sleep(50000);} catch (InterruptedException e) {throw new RuntimeException(e);}finally {lock.unlock();log.info("NO1解锁成功");}return "NO1线程已经走完成!";}@GetMapping("no2")public String TestRedisson02(){RLock lock = redissonSingle.getLock("my-redisson-lock");lock.lock();try {log.info("NO2加锁成功,正在处理业务逻辑》》》》》");System.out.println("好长的业务");Thread.sleep(50000);} catch (InterruptedException e) {throw new RuntimeException(e);}finally {lock.unlock();log.info("NO2解锁成功");}return "NO2线程已经走完成!";}/*** 读写锁*   RReadWriteLock readWriteLock = redissonSingle.getReadWriteLock("my-lock");*         RLock rLock = readWriteLock.readLock();*         rLock.lock();*         rLock.unlock();*   读写锁: 读写锁是一个分布式锁,它允许多个线程同时读,但是只允许一个线程写,写操作的时候,读操作会被阻塞,*/@GetMapping("read")public String TestReadLock(){RReadWriteLock readWriteLock = redissonSingle.getReadWriteLock("my-lock");RLock rLock = readWriteLock.readLock();rLock.lock();String s = "";try {log.info("读写锁操作中,正在处理业务逻辑》》》》》");s = UUID.randomUUID().toString();redisTemplate.opsForValue().set("redisson:readWriteLock",s,200, TimeUnit.SECONDS);Thread.sleep(5000);}catch (Exception e){e.printStackTrace();}finally {rLock.unlock();}return s;}@GetMapping("writel")public String TestWriteLock(){RReadWriteLock readWriteLock = redissonSingle.getReadWriteLock("my-lock");RLock rLock = readWriteLock.writeLock();rLock.lock();String s = "";try {log.info("读锁操作中,正在处理业务逻辑》》》》》");String key = (String) redisTemplate.opsForValue().get("redisson:readWriteLock");if (!StringUtils.isEmpty(key)){s = key;}}catch (Exception e){e.printStackTrace();}finally {rLock.unlock();}return s;}/*** 闭锁*  RCountDownLatch door = redissonSingle.getCountDownLatch("door");*             door.trySetCount(5);*             door.await();**             door.countDown();*  闭锁: 闭锁是一个分布式闭锁,它允许一个或多个线程等待,直到其他线程完成一系列操作,然后才继续执行。*/@GetMapping("/lockDoor")public String lockDoor(){try {RCountDownLatch door = redissonSingle.getCountDownLatch("door");door.trySetCount(5);door.await();} catch (InterruptedException e) {throw new RuntimeException(e);}return "放假了。。。。。";}@GetMapping("/gogo/{id}")public String gogo(@PathVariable("id")String id){RCountDownLatch door = redissonSingle.getCountDownLatch("door");door.countDown();return id+"班的人都走了。。。。。";}@GetMapping("/modify")public String modifyData(){RLock lock = redissonSingle.getLock("my_modify_locl");if (!lock.tryLock()){return "修改失败,当前信息正在被人修改";}try {System.out.println("运行一个超长代码中");Thread.sleep(50000);return "修改成功";}catch (Exception e){e.printStackTrace();}finally {lock.unlock();}return "最后的代码";}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/15293.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

虚拟机上部署java微服务

在Windows服务器上安装Ubuntu系统&#xff0c;先安装虚拟机&#xff0c;然后再虚拟机上安装Ubuntu系统 启动虚拟机上的Ubuntu系统&#xff0c;然后安装jdk。安装好的Ubuntu系统是带桌面版的&#xff0c;需要打开 “终端” 控制台&#xff0c;通过命令行交互的方式部署程序&…

git 合并多个commit 使分支保持一次提交

1.控制台输入 git log 查看commit历史 找到历史提交sha 2.控制台输入 git rebase -i d0c5de8f7ca8e58fef347b36dd6b0f42f551cdb4 进入变基 3.输入英文i进入VM输入模式 4.保留第一行的pick 后面的pick改为s 5.esc退出输入模式 6.输入:wq保存退出 7.输入英文i进入VM输入模式…

从0开始实现一个博客系统 (SSM 实现)

相关技术 Spring Spring Boot Spring MVC MyBatis Html Css JS 实现功能 用户注册 - 密码加盐加密 (md5 加密)前后端用户信息存储 - 令牌技术用户登录 - (使用 拦截器 做登录校验)博客的增删改查后端数据返回前端, 采用 SpringBoot 做统一功能处理和统一异常处理 数据…

软考-程序员 知识点与部分真题梳理

软考-程序员 知识点与部分真题梳理 参照《程序员教程》第五版划分类别&#xff1b; 持续更新中… 计算机系统基础知识 如何理解和处理浮点数的加减法运算 在计算机科学中&#xff0c;处理浮点数的表示和运算是基础且关键的&#xff0c;尤其是在进行科学计算、图形处理和数据分…

V2I(车与基础设施)介绍

V2I&#xff08;车与基础设施&#xff09;介绍 一、V2I技术概述 V2I&#xff08;Vehicle-to-Infrastructure&#xff09;技术&#xff0c;全称汽车与基础设施通讯&#xff0c;也被称为信号灯系统。它通过无线通信技术&#xff0c;为车载智能交通运输系统设立了专门的通信频段…

【网络】为什么udp协议报头有长度字段,而tcp没有

引言&#xff1a; 在网络通信中&#xff0c;UDP&#xff08;用户数据报协议&#xff09;和TCP&#xff08;传输控制协议&#xff09;是两种常用的传输层协议。它们在设计和功能上有一些不同之处&#xff0c;其中之一就是报头中的长度字段。本文将深入探讨UDP和TCP协议中长度字…

SpringCloud Alibaba详解:打造高可用的分布式系统

SpringCloud Alibaba是一个基于Spring Cloud的微服务开发框架&#xff0c;它集成了阿里巴巴的一系列中间件和工具&#xff0c;能够快速构建高可用的分布式系统。在本文中&#xff0c;将详细介绍如何使用SpringCloud Alibaba来打造高可用的分布式系统&#xff0c;并通过代码案例…

第十一课,end关键字、简单while循环嵌套、初识for循环

一&#xff0c;end关键字 end关键字用于在print输出的内容后面声明结束的字符&#xff0c;我们之前学过并且十分了解print是默认输出内容之后跟着换行的&#xff0c;如果我们不希望换行而希望使用其它字符来代替换行&#xff0c;就可以用end关键字来实现 特殊的&#xff0c;en…

k8s笔记 | 高度调度

CronJob计划任务 简介&#xff1a;在k8s中周期性运行计划任务&#xff0c;与linux中的crontab相同&#xff1b;注意点 CornJob执行的时间是controller-manager的时间&#xff0c;所以一定要确保controller-manager的时间是准确的&#xff0c;另外cornjob cron表达式 文章参…

xjoi题库一级三段题解(c语言版)

浮点数 时间&#xff1a;0.2 空间&#xff1a;32M 题目描述&#xff1a; 小鹦鹉正在学习浮点数&#xff0c;你跟他说一个浮点数&#xff0c;他立刻就能学会。 输入一个浮点数&#xff0c;输出这个浮点数。 输入格式&#xff1a; 输入一个浮点数 输出格式&#xff1a; 输出一个…

2024.5.25AcWing刷题记录-排序篇

一、786. 第k个数 - AcWing题库 三路快速排序 import random def func(nums, start, end):if start > end:return idx random.randint(start, end)base nums[idx]i, j, m start, start, end 1while j < m:if nums[j] < base:nums[i], nums[j] nums[j], nums[i]…

Redis机制-Redis缓存穿透,击穿,雪崩理解等问题的理解和学习

目录 一 缓存穿透问题 二 缓存击穿问题 三 缓存雪崩问题&#xff1a; 图1 正常的Redis缓存流程 一 缓存穿透问题 我们都知道Redis是一个存储键值对的非关系型数据库&#xff0c;那么当用户进行查询的时候&#xff0c;势必会从前端发起请求&#xff0c;从而数据从Redis缓存…

内网穿透--Frp-简易型(速成)-上线

免责声明:本文仅做技术交流与学习... 目录 frp项目介绍: 一图通解: ​编辑 1-下载frp 2-服务端(server)开启frp口 3-kali客户端(client)连接frp服务器 4-kali生成马子 5-kali监听 6-马子执行-->成功上线 frp项目介绍: GitHub - fatedier/frp: A fast reverse proxy…

论文精读-SwinIR Image Restoration Using Swin Transformer

论文精读-SwinIR: Image Restoration Using Swin Transformer SwinIR:使用 Swin Transformer进行图像恢复 参数量&#xff1a;SR 11.8M、JPEG压缩伪影 11.5M、去噪 12.0M 优点&#xff1a;1、提出了新的网络结构。它采用分块设计。包括浅层特征提取&#xff1a;cnn提取&#…

Verilog实战学习到RiscV - 1 : Yosys 综合

Yosys 综合 实例 一般 FPGA IDE 的第一步都是RTL 综合&#xff08;Synthesis&#xff09;。之后就能看到数字电路图了。然后可以做RTL 级的仿真模拟。 直接上代码&#xff0c;这里我们看一个简单的加法器来学习。 module adder(input [7:0] a,input [7:0] b, input …

Java延时队列取消未支付的订单 之 重启服务任务丢失

一、定义延迟任务类 package com.activity.domain;import java.util.concurrent.Delayed; import java.util.concurrent.TimeUnit;/*** 延迟任务类*/ public class DelayedCancellation implements Delayed {private String order;private final long delayTime; // 延迟时间p…

链表类型的无界阻塞队列-LinkedBlockingQueue

一:LinkedBlockingQueue介绍 1:LinkedBlockingQueue是一个基于链表实现的阻塞队列,默认情况下,该阻塞队列的大小为Integer.MAX_VALUE,由于这个数值特别大,所以 LinkedBlockingQueue 也被称作无界队列,代表它几乎没有界限,队列可以随着元素的添加而动态增长,但是如果没…

智能体之斯坦福AI小镇(Generative Agents: Interactive Simulacra of Human Behavior)

相关代码地址见文末 论文地址&#xff1a;Generative Agents: Interactive Simulacra of Human Behavior | Proceedings of the 36th Annual ACM Symposium on User Interface Software and Technology 1.概述 论文提出了一种多个智能体进行协同&#xff0c;进而模拟可信的人…

Python燃气轮机汽车钢棒整流电路控制图统计模型过程潜力分析

&#x1f3af;要点 &#x1f3af;活塞模拟器&#xff1a;&#x1f58a;控制图过程能力分析&#xff1a;Cp 对过程提供在规格上限和下限内的输出的潜力度量&#xff0c;Cpk中心过程能力指数&#xff0c;Cpl估计仅包含规格下限过程能力&#xff0c;Cpu估计仅包含规格上限过程能力…

Linux系统下Mysql忘记密码怎么解决

一、对Mysql配置文件进行设置 1、找到/etc/mysql/my.cnf路径下&#xff0c;用Vi命令编辑my.cnf配置文件&#xff0c;命令如下&#xff1a; # 以管理员身份登录 sudo su # 输入管理员密码 # 登录成功后&#xff0c;找到Mysql的配置文件-->Mysql配置文件默认在此 cd /etc/my…