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

news2024/11/26 8:57:21

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: 8081
  servlet:
    context-path: /api
spring:
  redis:
    host: 服务器ip
    port: 6379
#    password: 123456
    timeout: 60000
    database: 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://";


    /**
     * 自动装配
     *
     */
    @Bean
    RedissonClient 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 {

    @Resource
    RedissonClient redissonSingle;
    @Resource
    RedisTemplate<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.coloradmin.cn/o/1693845.html

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

相关文章

【CTF Web】CTFShow web4 Writeup(SQL注入+PHP+字符型注入)

web4 1 管理员阿呆又失败了&#xff0c;这次一定要堵住漏洞 解法 注意到&#xff1a; <!-- flag in id 1000 -->拦截很多种字符&#xff0c;连 select 也不给用了。 if(preg_match("/or|\-|\\\|\/|\\*|\<|\>|\!|x|hex|\(|\)|\|select/i",$id)){die(&q…

抖音运营_如何做出优质的短视频

目录 一 短视频内容的构成 1 图像 2 字幕 3 声音 4 特效 5 描述 6 评论 二 短视频的热门类型 1 颜值圈粉类 2 知识教学类 3 幽默搞笑类 4 商品展示类 5 才艺技能类 6 评论解说类 三 热门短视频的特征 1 产生共鸣 2 正能量 3 紧跟热点话题 4 富有创意 四 短视…

计算机网络套接字知识(非常详细)从零基础入门到精通

本节重点 认识IP地址, 端口号, 网络字节序等网络编程中的基本概念; 学习socket api的基本用法; 一、预备知识 1.理解源IP地址和目的IP地址 ⭐在IP数据包头部中&#xff0c;有两个IP地址&#xff0c;分别叫做源IP地址和目的IP地址。 思考: 我们光有IP地址就可以完成通信了…

spring boot 集成mongodb

引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-mongodb</artifactId><version>2.2.0.RELEASE</version></dependency>配置db: spring:data:mongodb:host: 127.0.…

【C++高阶(一)】继承

目录 一、继承的概念 1.继承的基本概念 2.继承的定义和语法 3.继承基类成员访问方式的变化 ​编辑 4.总结 二、基类和派生类对象赋值转换 三、继承中的作用域 四、派生类的默认成员函数 1.派生类中的默认构造函数 2.派生类中的拷贝构造函数 3.派生类中的移动构造函数…

Kubeadm安装部署k8s集群、踩坑日常

背景 ​ Docker是一个非常流行的容器化平台&#xff0c;它可以让我们方便构建、打包、发布和运行容器化应用程序。但是&#xff0c;在生产环境中&#xff0c;我们可能需要处理成百上千个容器&#xff0c;需要更好的管理这些容器&#xff0c;这就是Kubernetes(K8S)的用武之地。…

vue15:记事本vue指令案例

效果图&#xff1a; vue指令 代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>帅临记事本</…

prometheusgrafananode_export搭建监控平台

一、环境要求 1、docker安装docker环境 2、docker安装prometheus 3、docker安装grafana 4、node-exportor(安装在被测服务器上) 5、我的服务器是Ubuntu 二、docker 安装prometheus 1、下载Prometheus镜像 docker pull prom/prometheus 2、检查端口是否被占用 安装netstat命…

24款奔驰S450升级原厂后排娱乐系统 主动氛围灯有哪些功能

24款奔驰S400豪华升级原厂主动氛围灯与后排娱乐系统&#xff1a;画蛇添足还是锦上添花&#xff1f; 在当今汽车市场竞争激烈的环境下&#xff0c;汽车制造商们为了满足消费者的多元化需求&#xff0c;不断推出各种升级配置和豪华版本。24款奔驰S400豪华版作为奔驰S级的一款重要…

碌时刻必备!微信自动回复让你告别消息堆积

在忙碌的时候&#xff0c;我们往往会面临消息堆积如山的情况。无法及时回复消息不仅容易造成交流障碍&#xff0c;还可能错过重要的机会。 但是现在&#xff0c;有一个神奇的工具——个微管理系统&#xff0c;可以帮助我们轻松应对这个问题 &#xff0c;实现微信自动回复。 首…

AIGC-风格迁移-style Injection in Diffusion-CVPR2024HighLight-论文精度

Style Injection in Diffusion: A Training-free Approach for Adapting Large-scale Diffusion Models for Style Transfer-CVPR2024HighLight 代码&#xff1a;https://github.com/jiwoogit/StyleID 论文&#xff1a;https://jiwoogit.github.io/StyleID_site/ 为了解决风格迁…

WXSS模板样式-全局样式和局部样式

一、WXSS 1.WXSS WXSS(WeiXin Style Sheets)是一套样式语言&#xff0c;用于美化WXML的组件样式&#xff0c;类似于网页开发中的CSS 2.WXSS和CSS的关系 WXSS具有CSS大部分特性&#xff0c;同时&#xff0c;WXSS还对CSS进行了扩充以及修改&#xff0c;以适应微信小程序的开发…

详解 Spring MVC(Spring MVC 简介)

什么是 Spring MVC&#xff1f; Spring MVC 是 Spring 框架提供的一个基于 MVC 模式的轻量级 Web 框架&#xff0c;是 Spring 为表示层开发提供的一整套完整的解决方案&#xff0c;Spring MVC 使用了 MVC 架构模式&#xff0c;将 Web 层职责解耦&#xff0c;基于请求驱动模型&…

26计算机操作系统408考研-操作系统进程与线程篇章(三)

操作系统进程与线程篇章 ` 文章目录 操作系统进程与线程篇章前言一、进程概念进程控制块进程创建进程终止进程的阻塞和唤醒进程唤醒进程挂起和激活线程多线程线程实现与线程模型总结互斥和同步并发原理硬件同步信号量机制信号量的应用管程经典同步问题消息传递前言 一、进程概…

Qt 科目一考试系统(有源码)

项目源码和资源&#xff1a;科目一考试系统: qt实现科目一考试系统 一.项目概述 该项目是一个基于Qt框架开发的在线考试系统&#xff0c;主要实现了考试题目的随机抽取、考试时间限制、成绩统计等功能。用户可以通过界面操作进行考试&#xff0c;并查看自己的考试成绩。 二.技…

清理安卓手机广告

保存脚本另存为 Fuck_AD.sh&#xff0c;在手机执行后体验效果。 echo ""echo " " echo " - 开始执行清理广告库文件" sleep 3files(/data/app/*/*/lib/arm64/libpangleflipped.so/data/app/*/*/lib/arm64/libzeus_direct_dex.so/data/app/*/*/l…

力扣--哈希表13.罗马数字转整数

首先我们可以知道&#xff0c;一个整数&#xff0c;最多由2个罗马数字组成。 思路分析 这个方法能够正确将罗马数字转换为阿拉伯数字的原因在于它遵循了罗马数字的规则&#xff0c;并且对这些规则进行了正确的编码和处理。 罗马数字规则 罗马数字由以下字符组成&#xff1a…

第八届能源、环境与材料科学国际学术会议(EEMS 2024)

文章目录 一、重要信息二、大会简介三、委员会四、征稿主题五、论文出版六、会议议程七、出版信息八、征稿编辑 一、重要信息 会议官网&#xff1a;http://ic-eems.com主办方&#xff1a;常州大学大会时间&#xff1a;2024年06月7-9日大会地点&#xff1a;新加坡 Holiday Inn …

langchian进阶二:LCEL表达式,轻松进行chain的组装

LangChain表达式语言-LCEL&#xff0c;是一种声明式的方式&#xff0c;可以轻松地将链条组合在一起。 你会在这些情况下使用到LCEL表达式: 流式支持 当你用LCEL构建你的链时&#xff0c;你可以得到最佳的首次到令牌的时间(输出的第一块内容出来之前的时间)。对于一些链&#…

C语言.数据结构.顺序表

1.顺序表的概念及结构 1.1线性表 线性表&#xff08;linear list&#xff09;是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构&#xff0c;常见的线性表&#xff1a;顺序表、链表、栈、队列、字符串… 线性表在逻辑上是线性结构&#xff0c;…