SpringBoot整合redisson实现分布式锁

SpringBoot整合redisson实现分布式锁

本文主要通过 SpringBoot 整合 redisson 来实现分布式锁,并结合 demo 测试结果。

在这里插入图片描述

1、pom依赖

<?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>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.4</version>
        <relativePath/>
    </parent>
	
    <groupId>com.example</groupId>
    <artifactId>springboot-redission</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springboot-redission</name>
    <description>springboot-redission</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!--redis-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

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

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.20</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

2、配置信息

spring:
  # redis
  redis:
    host: 127.0.0.1
    port: 6379
    jedis:
      pool:
        # 连接池最大连接数(使用负值表示没有限制)
        max-active: 100
        # 连接池中的最小空闲连接
        max-idle: 10
        # 连接池最大阻塞等待时间(使用负值表示没有限制)
        max-wait: -1
      # 连接超时时间(毫秒)
      timeout: 5000
      # 默认是索引为0的数据库
      database: 0

3、配置类

package com.example.config;

import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;

/**
 * redisson配置
 */

@Configuration
public class RedissonConfig {

    @Value("${spring.redis.host}")
    private String host;

    @Value("${spring.redis.port}")
    private String port;

    @Value("${spring.redis.password:}")
    private String password;

    @Bean
    public RedissonClient redissonClient() {
        Config config = new Config();
        //单节点
        config.useSingleServer().setAddress("redis://" + host + ":" + port);
        if (StringUtils.isEmpty(password)) {
            config.useSingleServer().setPassword(null);
        } else {
            config.useSingleServer().setPassword(password);
        }
        return Redisson.create(config);
    }
}

4、Redisson 工具类

package com.example.utils;

import org.redisson.api.RCountDownLatch;
import org.redisson.api.RLock;
import org.redisson.api.RSemaphore;

import java.util.concurrent.TimeUnit;

public interface DistributedLocker {

    RLock lock(String lockKey);

    RLock lock(String lockKey, int timeout);

    RLock lock(String lockKey, TimeUnit unit, int timeout);

    boolean tryLock(String lockKey, TimeUnit unit, int waitTime, int leaseTime);

    void unlock(String lockKey);

    void unlock(RLock lock);

    RCountDownLatch getCountDownLatch(String name);

    RSemaphore getSemaphore(String name);
}
package com.example.utils;

import org.redisson.api.RCountDownLatch;
import org.redisson.api.RLock;
import org.redisson.api.RSemaphore;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

@Component
public class RedisDistributedLocker implements DistributedLocker {

    @Autowired
    private RedissonClient redissonClient;

    @Override
    public RLock lock(String lockKey) {
        RLock lock = redissonClient.getLock(lockKey);
        lock.lock();
        return lock;
    }

    @Override
    public RLock lock(String lockKey, int leaseTime) {
        RLock lock = redissonClient.getLock(lockKey);
        lock.lock(leaseTime, TimeUnit.SECONDS);
        return lock;
    }

    @Override
    public RLock lock(String lockKey, TimeUnit unit ,int timeout) {
        RLock lock = redissonClient.getLock(lockKey);
        lock.lock(timeout, unit);
        return lock;
    }

    @Override
    public boolean tryLock(String lockKey, TimeUnit unit, int waitTime, int leaseTime) {
        RLock lock = redissonClient.getLock(lockKey);
        try {
            return lock.tryLock(waitTime, leaseTime, unit);
        } catch (InterruptedException e) {
            return false;
        }
    }

    @Override
    public void unlock(String lockKey) {
        RLock lock = redissonClient.getLock(lockKey);
        lock.unlock();
    }

    @Override
    public void unlock(RLock lock) {
        lock.unlock();
    }

    @Override
    public RCountDownLatch getCountDownLatch(String name) {
        return redissonClient.getCountDownLatch(name);
    }

    @Override
    public RSemaphore getSemaphore(String name) {
        return redissonClient.getSemaphore(name);
    }
}
package com.example.utils;

import org.redisson.api.RCountDownLatch;
import org.redisson.api.RLock;
import org.redisson.api.RSemaphore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
 * redis分布式锁帮助类
 *
 * @author gourd
 */
@Component
public class RedisLockUtil {

    @Autowired
    private DistributedLocker distributedLocker;

    /**
     * 加锁
     *
     * @param lockKey
     * @return
     */
    public  RLock lock(String lockKey) {
        return distributedLocker.lock(lockKey);
    }

    /**
     * 释放锁
     *
     * @param lockKey
     */
    public  void unlock(String lockKey) {
        distributedLocker.unlock(lockKey);
    }

    /**
     * 释放锁
     *
     * @param lock
     */
    public  void unlock(RLock lock) {
        distributedLocker.unlock(lock);
    }

    /**
     * 带超时的锁
     *
     * @param lockKey
     * @param timeout 超时时间   单位:秒
     */
    public  RLock lock(String lockKey, int timeout) {
        return distributedLocker.lock(lockKey, timeout);
    }

    /**
     * 带超时的锁
     *
     * @param lockKey
     * @param unit    时间单位
     * @param timeout 超时时间
     */
    public  RLock lock(String lockKey, int timeout, TimeUnit unit) {
        return distributedLocker.lock(lockKey, unit, timeout);
    }

    /**
     * 尝试获取锁
     *
     * @param lockKey
     * @param waitTime  最多等待时间
     * @param leaseTime 上锁后自动释放锁时间
     * @return
     */
    public  boolean tryLock(String lockKey, int waitTime, int leaseTime) {
        return distributedLocker.tryLock(lockKey, TimeUnit.SECONDS, waitTime, leaseTime);
    }

    /**
     * 尝试获取锁
     *
     * @param lockKey
     * @param unit      时间单位
     * @param waitTime  最多等待时间
     * @param leaseTime 上锁后自动释放锁时间
     * @return
     */
    public  boolean tryLock(String lockKey, TimeUnit unit, int waitTime, int leaseTime) {
        return distributedLocker.tryLock(lockKey, unit, waitTime, leaseTime);
    }

    /**
     * 获取计数器
     *
     * @param name
     * @return
     */
    public  RCountDownLatch getCountDownLatch(String name) {
        return distributedLocker.getCountDownLatch(name);
    }

    /**
     * 获取信号量
     *
     * @param name
     * @return
     */
    public  RSemaphore getSemaphore(String name) {
        return distributedLocker.getSemaphore(name);
    }
}

5、启动类

package com.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringbootRedissionApplication {

	public static void main(String[] args) {
		SpringApplication.run(SpringbootRedissionApplication.class, args);
	}

}

6、测试

模拟并发测试

package com.example.controller;

import com.example.utils.RedisLockUtil;
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.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * redis分布式锁控制器
 */

@RestController
@RequestMapping("/redisson")
@Slf4j
public class RedissonLockController {

    @Autowired
    private RedisLockUtil redisLockUtil;

    /**
     * 锁测试共享变量
     */
    private Integer lockCount = 10;

    /**
     * 无锁测试共享变量
     */
    private Integer count = 10;

    /**
     * 模拟线程数
     */
    private static int threadNum = 10;

    /**
     * 模拟并发测试加锁和不加锁
     *
     * @return
     */
    @GetMapping("/test")
    public void lock() {
        // 计数器
        final CountDownLatch countDownLatch = new CountDownLatch(1);
        for (int i = 0; i < threadNum; i++) {
            MyRunnable myRunnable = new MyRunnable(countDownLatch);
            Thread myThread = new Thread(myRunnable);
            myThread.start();
        }
        // 释放所有线程
        countDownLatch.countDown();
    }

    /**
     * 加锁测试
     */
    private void testLockCount() {
        String lockKey = "lock-test";
        try {
            // 加锁,设置超时时间2s
            redisLockUtil.lock(lockKey, 2, TimeUnit.SECONDS);
            lockCount--;
            log.info("lockCount值:" + lockCount);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        } finally {
            // 释放锁
            redisLockUtil.unlock(lockKey);
        }
    }

    /**
     * 无锁测试
     */
    private void testCount() {
        count--;
        log.info("count值:" + count);
    }


    public class MyRunnable implements Runnable {
        /**
         * 计数器
         */
        final CountDownLatch countDownLatch;

        public MyRunnable(CountDownLatch countDownLatch) {
            this.countDownLatch = countDownLatch;
        }

        @Override
        public void run() {
            try {
                // 阻塞当前线程,直到计时器的值为0
                countDownLatch.await();
            } catch (InterruptedException e) {
                log.error(e.getMessage(), e);
            }
            // 无锁操作
            testCount();
            // 加锁操作
            testLockCount();
        }

    }
}

调用接口后打印值:http://localhost:8080/redisson/test

2022-08-16 19:52:02.955  INFO 13112 --- [      Thread-15] c.e.controller.RedissonLockController    : count值:4
2022-08-16 19:52:02.955  INFO 13112 --- [      Thread-14] c.e.controller.RedissonLockController    : count值:5
2022-08-16 19:52:02.955  INFO 13112 --- [      Thread-18] c.e.controller.RedissonLockController    : count值:6
2022-08-16 19:52:02.955  INFO 13112 --- [      Thread-11] c.e.controller.RedissonLockController    : count值:7
2022-08-16 19:52:02.955  INFO 13112 --- [      Thread-16] c.e.controller.RedissonLockController    : count值:1
2022-08-16 19:52:02.955  INFO 13112 --- [      Thread-12] c.e.controller.RedissonLockController    : count值:5
2022-08-16 19:52:02.955  INFO 13112 --- [      Thread-13] c.e.controller.RedissonLockController    : count值:4
2022-08-16 19:52:02.955  INFO 13112 --- [      Thread-19] c.e.controller.RedissonLockController    : count值:2
2022-08-16 19:52:02.956  INFO 13112 --- [      Thread-20] c.e.controller.RedissonLockController    : count值:0
2022-08-16 19:52:02.955  INFO 13112 --- [      Thread-17] c.e.controller.RedissonLockController    : count值:3
2022-08-16 19:52:03.074  INFO 13112 --- [      Thread-11] c.e.controller.RedissonLockController    : lockCount值:9
2022-08-16 19:52:03.100  INFO 13112 --- [      Thread-12] c.e.controller.RedissonLockController    : lockCount值:8
2022-08-16 19:52:03.106  INFO 13112 --- [      Thread-17] c.e.controller.RedissonLockController    : lockCount值:7
2022-08-16 19:52:03.116  INFO 13112 --- [      Thread-13] c.e.controller.RedissonLockController    : lockCount值:6
2022-08-16 19:52:03.139  INFO 13112 --- [      Thread-14] c.e.controller.RedissonLockController    : lockCount值:5
2022-08-16 19:52:03.149  INFO 13112 --- [      Thread-19] c.e.controller.RedissonLockController    : lockCount值:4
2022-08-16 19:52:03.157  INFO 13112 --- [      Thread-16] c.e.controller.RedissonLockController    : lockCount值:3
2022-08-16 19:52:03.163  INFO 13112 --- [      Thread-18] c.e.controller.RedissonLockController    : lockCount值:2
2022-08-16 19:52:03.168  INFO 13112 --- [      Thread-20] c.e.controller.RedissonLockController    : lockCount值:1
2022-08-16 19:52:03.179  INFO 13112 --- [      Thread-15] c.e.controller.RedissonLockController    : lockCount值:0

测试结果:

根据打印结果可以明显看到,未加锁的 count-- 后值是乱序的,而加锁后的结果和我们预期的一样。

由于条件问题没办法测试分布式的并发,只能模拟单服务的这种并发,但是原理是一样,希望对大家有帮助。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Linux】 开始使用 gcc 吧!!!

Linux 1 认识gcc2 背景知识3 gcc 怎样完成 &#xff1f;3.1 预处理预处理^条件编译 3.2 编译3.3 汇编3.4 链接 4 函数库5 gcc 基本选项Thanks♪(&#xff65;ω&#xff65;)&#xff89;谢谢阅读下一篇文章见&#xff01;&#xff01;&#xff01; 1 认识gcc 我们在windows环…

【LIBS】交叉编译TCPDUMP

目录 1. 安装编译工具2. 设置环境变量3. 编译libpcap3.1 安装依赖3.2 交叉编译 4. 编译TCPDUMP4.1 克隆仓库与生成构建环境4.2 静态链接LIBPCAP4.3 动态链接LIBPCAP4.4 构建与安装 5. 查看交叉编译结果5.1 文件布局 1. 安装编译工具 sudo apt-get install -y autoconf automak…

SaaS系统如何助力企业数字化转型

随着科技的快速发展&#xff0c;数字化转型已经成为企业适应市场变化、提高竞争力的必要手段。在这个过程中&#xff0c;SaaS&#xff08;软件即服务&#xff09;系统以其独特的优势&#xff0c;正在成为越来越多企业的首选。乔拓云SaaS系统作为这一领域的佼佼者&#xff0c;更…

谷歌出品!读懂 QUIC 协议:更快、更高效的通信协议

QUIC结构 QUIC协议模型如下图所示&#xff0c;其放弃了TCP∕IP网络中使用五元组(源IP,源端口,目的IP,目的端口,协议标识符)来唯一标识一条连接的方式,而使用一个全局唯一的随机生成的ID(即Connection ID) 来标识一条连接。 由低向上分层讨论QUIC协议&#xff1a; •UDP层:在U…

1990-2019年城市维度区域创新创业指数面板数据/地级市创新创业指数面板数据

1990-2019年城市维度区域创新创业指数面板数据/地级市创新创业指数面板数据 1、时间&#xff1a;1990-2019年 2、范围&#xff1a;地级市&#xff08;290&#xff09; 3、指标&#xff1a;序号、年份、城市码、城市、总维度&#xff1a;总量指数得分、人均得分、单位面积得分…

应用协议漏洞

应用协议漏洞 一、rsync rsync是Linux下一款数据备份工具&#xff0c;支持通过rsync协议、ssh协议进行远程文件传输。其中rsync协议默认监听873端口 1.未授权访问 打开靶场 判断漏洞是否存在 rsync rsync://目标ip:端口读取文件 rsync rsync://47.99.49.128:873/src/tmp/下…

访问者模式-C#实现

该实例基于WPF实现&#xff0c;直接上代码&#xff0c;下面为三层架构的代码。 一 Model using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;namespace 设计模式练习.Model.访问者模式 {public class Com…

JRT的无源码发布

之前介绍过JRT最大的特点就是业务脚本化。老javaer就会说你业务代码都在发布环境放着&#xff0c;那怎么代码保密&#xff0c;在发布环境别人随便改了启不是不安全&#xff0c;或者一些代码我就是不想让人看源码呢。 其实JRT的业务脚本化只是特性&#xff0c;不是代表就必须要…

如何进行H.265视频播放器EasyPlayer.js的中性化设置?

H5无插件流媒体播放器EasyPlayer属于一款高效、精炼、稳定且免费的流媒体播放器&#xff0c;可支持多种流媒体协议播放&#xff0c;可支持H.264与H.265编码格式&#xff0c;性能稳定、播放流畅&#xff0c;能支持WebSocket-FLV、HTTP-FLV&#xff0c;HLS&#xff08;m3u8&#…

C#用DateAndTime.DateDiff方法和TimeSpan分别计算时间间隔

目录 一、计算时间间隔的方法 1.用DateAndTime.DateDiff方法计算时间间隔 2.使用TimeSpan获取日期时间间隔 二、实例 1.示例一&#xff1a;用DateAndTime.DateDiff方法计算时间间隔 2.示例二&#xff1a;使用TimeSpan获取日期时间间隔 一、计算时间间隔的方法 1.用Date…

深入《羊了个羊》:从0到1的消除游戏开发

一、游戏简介 《羊了个羊》是一款备受欢迎的消除类游戏。玩家需要通过交换相邻的方块&#xff0c;使三个或更多相同方块连成一线&#xff0c;从而将它们消除。消除方块可以获得分数&#xff0c;并在全球排行榜上与其他玩家竞争。 设置项目结构 首先&#xff0c;在文本编辑器中…

【博客搭建记录贴】day4_Hexo基本操作,添加草稿并发布

目录 1.将项目导入到开发环境1.1 先把项目导入到IDEA中1.2 确认IDEA中服务器启动正常 2.Hexo基本操作: 添加草稿并发布2.1 生成一个草稿文件2.2 在页面上查看草稿3.3 将草稿正式发布 1.将项目导入到开发环境 我本地已经安装了 IntelliJ IDEA&#xff08;版本&#xff1a;社区版…

【modelsim使用】数据显示设置

本文介绍modelsim使用中数据的显示设置&#xff0c;定点小数的显示、模拟波形的显示、数据截位查看、信号颜色和行高设置的操作。 文章目录 定点小数显示模拟波形的显示选取信号的某几位组合查看信号颜色与行高设置 定点小数显示 使用modelsim进行仿真时&#xff0c;涉及到定点…

【GitHub项目推荐--一款美观的开源社区系统】【转载】

推荐一款开源社区系统&#xff0c;该系统基于主流的 Java Web 技术栈&#xff0c;如果你是一名 Java 新手掌握了基本 JavaEE 框架知识&#xff0c;可以拿本项目作为练手项目。 开源社区系统功能还算完善包含发布帖子、发布评论、私信、系统通知、点赞、关注、搜索、用户设置、…

【MySQL】内外连接

内外连接 一、内连接二、外连接1、左外连接2、右外连接 表的连接分为内连和外连。 一、内连接 内连接实际上就是利用where子句对两种表形成的笛卡儿积进行筛选。只不过为了让sql的可读性更好&#xff0c;我们使用其他的关键字进行内连接。 语法&#xff1a; SELECT ... FRO…

BGP路由协议通告原则

1仅将自己最优的路由发给BGP邻居 一般情况下,如果BGP Speaker学到去往同一网段的路由多于一条时,只会选择一条最优的路由给自己使用,即用来发布给邻居,同时上送给IP路由表。但是,由于路由器也会选择最优的路由给自己使用,所以BGP Speaker本身选择的最优的路由也不一定被…

简单模拟实现一个线程池

废话不多说之间上代码 import java.util.ArrayList; import java.util.List; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue;public class MyThreadPoolExecutor {private List<Thread> listnew ArrayList<>();pri…

Linux 离线安装Docker(脚本自动安装)

文章目录 1. 准备docker离线包2. 准备docker.service 系统配置文件3. 准备安装脚本和卸载脚本4. 安装5、docker存储 前言 关于服务器不能联网的情况&#xff0c;这样就没法用yum安装软件&#xff0c;docker也是如此&#xff1b;或者由于CentOS系统采用Yum 安装过程中很慢&#…

SpringBootAdmin邮件通知

在上一篇中我们学习到了 Admin Service Clustering 分布式缓存配置 &#xff0c;这一篇我们来学习&#xff0c;客户端离线&#xff0c;出现故障的时候&#xff0c;我们这么能及时知道呢&#xff0c;发现邮件通知也许是最简单的方式了&#xff01; 邮件通知 邮件通知将作为使用…

​在 Linux ​中管理用户

在 Linux 系统中&#xff0c;用户是系统资源的主要使用者&#xff0c;每个用户都有一个唯一的标识符&#xff08;用户ID&#xff09;。为了更好地组织和管理用户&#xff0c;Linux 还引入了用户组的概念。用户组是用户的集合&#xff0c;有助于更有效地分配权限和资源。 用户是…