SpringBoot整合redisson实现分布式锁

SpringBoot整合redisson实现分布式锁

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

SpringBoot整合redisson实现分布式锁_第1张图片

1、pom依赖


<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.0modelVersion>
    <parent>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-parentartifactId>
        <version>2.5.4version>
        <relativePath/>
    parent>
	
    <groupId>com.examplegroupId>
    <artifactId>springboot-redissionartifactId>
    <version>0.0.1-SNAPSHOTversion>
    <name>springboot-redissionname>
    <description>springboot-redissiondescription>

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

    <dependencies>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>

        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-testartifactId>
            <scope>testscope>
        dependency>

        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-data-redisartifactId>
        dependency>

        
        <dependency>
            <groupId>org.redissongroupId>
            <artifactId>redisson-spring-boot-starterartifactId>
            <version>3.10.6version>
        dependency>

        <dependency>
            <groupId>org.projectlombokgroupId>
            <artifactId>lombokartifactId>
            <version>1.18.20version>
        dependency>

    dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-maven-pluginartifactId>
            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-- 后值是乱序的,而加锁后的结果和我们预期的一样。

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

你可能感兴趣的:(spring,boot,spring,boot)