Redisson分布式锁实现

Redisson分布式锁实现

  • 1. 分布式锁概述
  • 2. 分布式锁实现
    • 2.1 maven依赖
    • 2.2 配置参数
    • 2.3 代码实现

1. 分布式锁概述

程序中的锁就是为了解决临界资源访问的同步性问题,而单机版的锁比如synchronized,Lock,ReentrantLock等是针对单个JVM实现的锁,而分布式锁是针对集群实现的锁。本文实现的是基于Redisson实现的分布式锁。

RedissonRedLock在创建锁的时候一定要注意避免死锁的问题,RedissonRedLock提供了三个参数,可以通过设置leaseTime有效时间避免死锁问题,l通过waitTime设置自旋时间。
lock.tryLock(waitTime, leaseTime, unit)
waitTime:等待时间,如果锁资源已经被占用会等待指定时间,超过改时间扔不能加锁,则立即返回失败。
leaseTime:锁的有效时间,加锁成功,超过该时间自动释放锁,。
unit:时间单位

关于基于Redis与Redisson分布式锁基本介绍,之前写过一篇有详细介绍,
Redis分布式锁详解:https://blog.csdn.net/m0_37583655/article/details/119966588

2. 分布式锁实现

2.1 maven依赖


<dependency>
    <groupId>com.google.guavagroupId>
    <artifactId>guavaartifactId>
    <version>30.1.1-jreversion>
dependency>
<dependency>
    <groupId>cn.hutoolgroupId>
    <artifactId>hutool-allartifactId>
    <version>5.6.3version>
dependency>
<dependency>
    <groupId>org.projectlombokgroupId>
    <artifactId>lombokartifactId>
    <optional>trueoptional>
dependency>
<dependency>
    <groupId>commons-langgroupId>
    <artifactId>commons-langartifactId>
    <version>2.6version>
    <scope>compilescope>
dependency>
<dependency>
    <groupId>com.alibabagroupId>
    <artifactId>fastjsonartifactId>
    <version>1.2.72version>
dependency>


<dependency>
    <groupId>org.redissongroupId>
    <artifactId>redissonartifactId>
    <version>3.7.3version>
dependency>

<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-configuration-processorartifactId>
    <optional>trueoptional>
dependency>

2.2 配置参数

application.properties

# 端口名称
server.port=8080
spring.application.name=autolog

# redisson
auto.redisson.address=redis://10.39.201.10:6379
auto.redisson.password=xyelbrp46j57JNtsuCfmvaHU
auto.redisson.clientName=
auto.redisson.thread=4
auto.redisson.codec=org.redisson.codec.JsonJacksonCodec
auto.redisson.connectionMinimumIdleSize=4
auto.redisson.idleConnectionTimeout=10000
auto.redisson.pingTimeout=1000
auto.redisson.connectTimeout=10000
auto.redisson.timeout=3000
auto.redisson.retryAttempts=1
auto.redisson.retryInterval=1500
auto.redisson.reconnectionTimeout=3000
auto.redisson.failedAttempts=2
auto.redisson.subscriptionsPerConnection=5
auto.redisson.subscriptionConnectionMinimumIdleSize=1
auto.redisson.subscriptionConnectionPoolSize=50
auto.redisson.connectionPoolSize=64
auto.redisson.database=0
auto.redisson.dnsMonitoring=false
auto.redisson.dnsMonitoringInterval=5000

2.3 代码实现

RedissonConfig

package com.zrj.autolog.lock;

import java.util.ArrayList;
import java.util.List;

import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.client.codec.Codec;
import org.redisson.config.Config;
import org.redisson.config.ReadMode;
import org.redisson.config.TransportMode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.util.ClassUtils;

import io.netty.channel.nio.NioEventLoopGroup;

/**
 * 分布式锁配置类
 *
 * @author zrj
 * @since 2021/12/9
 **/
@ConfigurationProperties(prefix = "auto.redisson")
public class RedissonConfig {

    private static Logger logger = LoggerFactory.getLogger(RedissonConfig.class);

    //format: 127.0.0.1:7000,127.0.0.1:7001;
    private String address;

    //single node properties
    private int connectionMinimumIdleSize = 10;
    private int idleConnectionTimeout = 10000;
    private int pingTimeout = 1000;
    private int connectTimeout = 10000;
    private int timeout = 3000;
    private int retryAttempts = 3;
    private int retryInterval = 1500;
    private int reconnectionTimeout = 3000;
    private int failedAttempts = 3;

    //multi nodes, password split by comma(,)
    private String password = null;
    private int subscriptionsPerConnection = 5;
    private String clientName = null;
    private int subscriptionConnectionMinimumIdleSize = 1;
    private int subscriptionConnectionPoolSize = 50;
    private int connectionPoolSize = 64;
    private int database = 0;
    private boolean dnsMonitoring = false;
    private int dnsMonitoringInterval = 5000;

    //master slave properties
    private ReadMode readMode = ReadMode.MASTER;

    //cluster properties
    private int scanInterval = 1000;


    private RedisClusterType type = RedisClusterType.REPLICATE;

    private int thread; //当前处理核数量 * 2

    private String codec = "org.redisson.codec.JsonJacksonCodec";

    public List<RedissonClient> redissons() throws Exception {
        List<RedissonClient> clients = new ArrayList<>();

        if (RedisClusterType.SINGLE.equals(type)) {
            clients.add(Redisson.create(configSingleNode(address, password)));
        } else if (RedisClusterType.MASTERSLAVE.equals(type)) {
            //TODO 3.2 master slave not support dns configure
            Config config = new Config();
            config.useMasterSlaveServers().setMasterAddress(address)
                    .addSlaveAddress(address)
                    .setMasterConnectionMinimumIdleSize(connectionMinimumIdleSize)
                    .setMasterConnectionPoolSize(connectionPoolSize)
                    .setSlaveConnectionMinimumIdleSize(connectionMinimumIdleSize)
                    .setSlaveConnectionPoolSize(connectionPoolSize)
                    .setReadMode(readMode)
                    .setDatabase(database)
                    .setSubscriptionsPerConnection(subscriptionsPerConnection)
                    .setClientName(clientName)
                    .setFailedSlaveCheckInterval(failedAttempts)
                    .setRetryAttempts(retryAttempts)
                    .setRetryInterval(retryInterval)
                    .setFailedSlaveCheckInterval(reconnectionTimeout)
                    .setTimeout(timeout)
                    .setConnectTimeout(connectTimeout)
                    .setIdleConnectionTimeout(idleConnectionTimeout)
                    .setPingTimeout(pingTimeout)
                    .setPassword(password);
            Codec codec = (Codec) ClassUtils.forName(getCodec(), ClassUtils.getDefaultClassLoader()).newInstance();
            config.setCodec(codec);
            config.setThreads(thread);
            config.setEventLoopGroup(new NioEventLoopGroup());
            config.setTransportMode(TransportMode.NIO);
            clients.add(Redisson.create(config));
        } else if (RedisClusterType.CLUSTER.equals(type)) {
            Config config = new Config();
            config.useClusterServers()
                    .addNodeAddress(address)
                    .setScanInterval(scanInterval)
                    .setSubscriptionsPerConnection(subscriptionsPerConnection)
                    .setClientName(clientName)
                    .setFailedSlaveCheckInterval(failedAttempts)
                    .setRetryAttempts(retryAttempts)
                    .setRetryInterval(retryInterval)
                    .setFailedSlaveCheckInterval(reconnectionTimeout)
                    .setTimeout(timeout)
                    .setConnectTimeout(connectTimeout)
                    .setIdleConnectionTimeout(idleConnectionTimeout)
                    .setPingTimeout(pingTimeout)
                    .setPassword(password);
            Codec codec = (Codec) ClassUtils.forName(getCodec(), ClassUtils.getDefaultClassLoader()).newInstance();
            config.setCodec(codec);
            config.setThreads(thread);
            config.setEventLoopGroup(new NioEventLoopGroup());
            config.setTransportMode(TransportMode.NIO);
            clients.add(Redisson.create(config));
        } else if (RedisClusterType.REPLICATE.equals(type)) {
            String[] nodes = address.split(",");
            if (password != null) {
                String[] passwords = password.split(",");
                int index = 0;
                for (String node : nodes) {
                    clients.add(Redisson.create(configSingleNode(node, passwords[index])));
                    index++;
                }
            } else {
                for (String node : nodes) {
                    clients.add(Redisson.create(configSingleNode(node, null)));
                }
            }
        } else if (RedisClusterType.SENTINEL.equals(type)) {
            //TODO
        }

        return clients;
    }

    private Config configSingleNode(String address, String password) throws Exception {
        Config config = new Config();
        config.useSingleServer().setAddress(address)
                .setConnectionMinimumIdleSize(connectionMinimumIdleSize)
                .setConnectionPoolSize(connectionPoolSize)
                .setDatabase(database)
                //.setDnsMonitoring(dnsMonitoring)
                .setDnsMonitoringInterval(dnsMonitoringInterval)
                .setSubscriptionConnectionMinimumIdleSize(subscriptionConnectionMinimumIdleSize)
                .setSubscriptionConnectionPoolSize(subscriptionConnectionPoolSize)
                .setSubscriptionsPerConnection(subscriptionsPerConnection)
                .setClientName(clientName)
                //.setFailedAttempts(failedAttempts)
                .setRetryAttempts(retryAttempts)
                .setRetryInterval(retryInterval)
                //.setReconnectionTimeout(reconnectionTimeout)
                .setTimeout(timeout)
                .setConnectTimeout(connectTimeout)
                .setIdleConnectionTimeout(idleConnectionTimeout)
                .setPingTimeout(pingTimeout)
                .setPassword(password);
        Codec codec = (Codec) ClassUtils.forName(getCodec(), ClassUtils.getDefaultClassLoader()).newInstance();
        config.setCodec(codec);
        config.setThreads(thread);
        config.setEventLoopGroup(new NioEventLoopGroup());
        config.setTransportMode(TransportMode.NIO);
        logger.info("inti the redisson client with config: {}", config.toJSON());
        return config;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public int getConnectionMinimumIdleSize() {
        return connectionMinimumIdleSize;
    }

    public void setConnectionMinimumIdleSize(int connectionMinimumIdleSize) {
        this.connectionMinimumIdleSize = connectionMinimumIdleSize;
    }

    public int getIdleConnectionTimeout() {
        return idleConnectionTimeout;
    }

    public void setIdleConnectionTimeout(int idleConnectionTimeout) {
        this.idleConnectionTimeout = idleConnectionTimeout;
    }

    public int getPingTimeout() {
        return pingTimeout;
    }

    public void setPingTimeout(int pingTimeout) {
        this.pingTimeout = pingTimeout;
    }

    public int getConnectTimeout() {
        return connectTimeout;
    }

    public void setConnectTimeout(int connectTimeout) {
        this.connectTimeout = connectTimeout;
    }

    public int getTimeout() {
        return timeout;
    }

    public void setTimeout(int timeout) {
        this.timeout = timeout;
    }

    public int getRetryAttempts() {
        return retryAttempts;
    }

    public void setRetryAttempts(int retryAttempts) {
        this.retryAttempts = retryAttempts;
    }

    public int getRetryInterval() {
        return retryInterval;
    }

    public void setRetryInterval(int retryInterval) {
        this.retryInterval = retryInterval;
    }

    public int getReconnectionTimeout() {
        return reconnectionTimeout;
    }

    public void setReconnectionTimeout(int reconnectionTimeout) {
        this.reconnectionTimeout = reconnectionTimeout;
    }

    public int getFailedAttempts() {
        return failedAttempts;
    }

    public void setFailedAttempts(int failedAttempts) {
        this.failedAttempts = failedAttempts;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public int getSubscriptionsPerConnection() {
        return subscriptionsPerConnection;
    }

    public void setSubscriptionsPerConnection(int subscriptionsPerConnection) {
        this.subscriptionsPerConnection = subscriptionsPerConnection;
    }

    public String getClientName() {
        return clientName;
    }

    public void setClientName(String clientName) {
        this.clientName = clientName;
    }

    public int getSubscriptionConnectionMinimumIdleSize() {
        return subscriptionConnectionMinimumIdleSize;
    }

    public void setSubscriptionConnectionMinimumIdleSize(int subscriptionConnectionMinimumIdleSize) {
        this.subscriptionConnectionMinimumIdleSize = subscriptionConnectionMinimumIdleSize;
    }

    public int getSubscriptionConnectionPoolSize() {
        return subscriptionConnectionPoolSize;
    }

    public void setSubscriptionConnectionPoolSize(int subscriptionConnectionPoolSize) {
        this.subscriptionConnectionPoolSize = subscriptionConnectionPoolSize;
    }

    public int getConnectionPoolSize() {
        return connectionPoolSize;
    }

    public void setConnectionPoolSize(int connectionPoolSize) {
        this.connectionPoolSize = connectionPoolSize;
    }

    public int getDatabase() {
        return database;
    }

    public void setDatabase(int database) {
        this.database = database;
    }

    public boolean isDnsMonitoring() {
        return dnsMonitoring;
    }

    public void setDnsMonitoring(boolean dnsMonitoring) {
        this.dnsMonitoring = dnsMonitoring;
    }

    public int getDnsMonitoringInterval() {
        return dnsMonitoringInterval;
    }

    public void setDnsMonitoringInterval(int dnsMonitoringInterval) {
        this.dnsMonitoringInterval = dnsMonitoringInterval;
    }

    public int getThread() {
        return thread;
    }

    public void setThread(int thread) {
        this.thread = thread;
    }

    public String getCodec() {
        return codec;
    }

    public void setCodec(String codec) {
        this.codec = codec;
    }

    public RedisClusterType getType() {
        return type;
    }

    public void setType(String type) {
        this.type = RedisClusterType.valueOf(type.toUpperCase());
    }

    public ReadMode getReadMode() {
        return readMode;
    }

    public void setReadMode(String readMode) {
        this.readMode = ReadMode.valueOf(readMode.toUpperCase());
    }

    public int getScanInterval() {
        return scanInterval;
    }

    public void setScanInterval(int scanInterval) {
        this.scanInterval = scanInterval;
    }
}

RedissonAutoConfigure

package com.zrj.autolog.lock;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * Redisson配置类
 *
 * @author zrj
 * @since 2021/12/9
 **/
@Configuration
@ConditionalOnClass(RedissonRedDisLock.class)
@EnableConfigurationProperties(RedissonConfig.class)
public class RedissonAutoConfigure {

    @Autowired
    private RedissonConfig config;

    @Bean
    @ConditionalOnMissingBean
    RedissonRedDisLock starterRedissonClient() {
        return new RedissonRedDisLock(config);
    }
}

RedisClusterType

package com.zrj.autolog.lock;

/**
 * redis集群类型
 *
 * @author zrj
 * @since 2021/12/9
 **/
public enum RedisClusterType {
    /**
     * redis集群类型
     */
    SINGLE,
    MASTERSLAVE,
    SENTINEL,
    CLUSTER,
    REPLICATE;
}

LockFailException

package com.zrj.autolog.lock;

/**
 * 分布式锁异常
 *
 * @author zrj
 * @since 2021/12/9
 **/
public class LockFailException extends Exception {

    private static final long serialVersionUID = -3816322588329303318L;

    private String message;

    public LockFailException(String message) {
        super(message);
        this.message = message;
    }

    @Override
    public String getMessage() {
        return message;
    }
}

DistributeLock

package com.zrj.autolog.lock;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;

/**
 * The distribute lock interface, support the lock, unlock action.
 *
 * @author zrj
 * @since 2021/12/9
 */
public interface DistributeLock {

    /**
     * try lock on lock key until the lock is available, and won't release the lock until call unlock()
     *
     * @param lockKey lock name
     * @return the lock object, use to unlock.
     */
    Lock lock(String lockKey) throws LockFailException;

    /**
     * try lock on lock key wait for timeout seconds, and won't release the lock until call unlock()
     *
     * @param lockKey lock name
     * @param timeout lock time out, unit is second
     * @return the lock object, use to unlock.
     */
    Lock lock(String lockKey, long timeout) throws LockFailException;

    /**
     * try lock on lock key wait for timeout unit, and won't release the lock until call unlock()
     *
     * @param lockKey lock name
     * @param unit    lock time out unit
     * @param timeout lock time out, -1 means no time out
     * @return
     */
    Lock lock(String lockKey, TimeUnit unit, long timeout) throws LockFailException;

    /**
     * try lock on lock key wait for timeout unit, and won't release the lock until call unlock()
     *
     * @param lockKey   lock name
     * @param unit      lock time out unit
     * @param timeout   lock time out, -1 means no time out
     * @param leaseTime lock lease time, -1 means no lease time out
     * @return
     */
    Lock lock(String lockKey, TimeUnit unit, long timeout, long leaseTime) throws LockFailException;

    /**
     * try lock on lock key wait for timeout unit, if can't lock return false; if lock success return true and will
     * lease the lock after lease time.
     *
     * @param lockKey
     * @param unit
     * @param waitTime
     * @param leaseTime
     * @return
     */
    boolean tryLock(String lockKey, TimeUnit unit, long waitTime, long leaseTime) throws LockFailException;

    /**
     * unlock the lock by the lock name.
     *
     * @param lockKey lock name
     */
    void unlock(String lockKey);

    /**
     * unlock the lock
     *
     * @param lock lock
     */
    void unlock(Lock lock);
}

RedissonRedDisLock

package com.zrj.autolog.lock;

import org.redisson.RedissonRedLock;
import org.redisson.api.RLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;

import static java.util.stream.Collectors.toList;

/**
 * The distribute lock interface, support the lock, unlock action.
 *
 * @author zrj
 * @since 2021/12/9
 **/
public class RedissonRedDisLock implements DistributeLock {

    private static Logger logger = LoggerFactory.getLogger(RedissonRedDisLock.class);

    private RedissonConfig config;

    private List<org.redisson.api.RedissonClient> redissionClientList;

    public RedissonRedDisLock(RedissonConfig config) {
        this.config = config;
    }

    @PostConstruct
    public void init() throws Exception {
        this.redissionClientList = config.redissons();
    }

    @PreDestroy
    public void destroy() {
        redissionClientList.stream().forEach(client -> {
            try {
                client.shutdown();
            } catch (Exception e) {
                logger.warn(e.getMessage(), e);
            }
        });
    }

    @Override
    public Lock lock(String lockKey) throws LockFailException {
        return lock(lockKey, null, -1, -1);
    }

    @Override
    public Lock lock(String lockKey, long waitTime) throws LockFailException {
        return lock(lockKey, TimeUnit.SECONDS, waitTime);
    }

    @Override
    public Lock lock(String lockKey, TimeUnit unit, long waitTime) throws LockFailException {
        return lock(lockKey, unit, waitTime, -1);
    }

    /**
     * 加锁
     *
     * @param lockKey   redisLock Key值
     * @param unit      时间单位
     * @param waitTime  等待时间,如果锁资源已经被占用会等待指定时间,超过改时间扔不能加锁,则立即返回失败
     * @param leaseTime 锁的有效时间,加锁成功,超过该时间自动释放锁
     * @return java.util.concurrent.locks.Lock
     */
    @Override
    public Lock lock(String lockKey, TimeUnit unit, long waitTime, long leaseTime) throws LockFailException {
        logger.info("【{}】lock use redlock with name {} start...", Thread.currentThread().getName(), lockKey);
        final String lockKeyFinal = lockKey;

        //获取锁队列
        List<RLock> rlocks = redissionClientList.stream().map(client -> client.getLock(lockKeyFinal)).collect(toList());
        //初始化锁对象
        RedissonRedLock lock = new RedissonRedLock(rlocks.toArray(new RLock[rlocks.size()]));
        try {
            if (lock.tryLock(waitTime, leaseTime, unit)) {
                logger.info("【{}】lock use redlock with name {} end...", Thread.currentThread().getName(), lockKey);
                return lock;
            } else {
                logger.error("lock use redlock with name {} failed.", lockKey);
                throw new LockFailException("lock use redlock with name " + lockKey + " failed.");
            }
        } catch (InterruptedException e) {
            logger.error("lock time expired");
            throw new LockFailException("lock use redlock with name " + lockKey + " failed for " + e.getMessage());
        }
    }

    @Override
    public boolean tryLock(String lockKey, TimeUnit unit, long waitTime, long leaseTime) {
        throw new UnsupportedOperationException("Red lock not support the try lock method.");
    }

    @Override
    public void unlock(String lockKey) {
        throw new UnsupportedOperationException("Red lock not support the unlock by name method, please use unlock(Lock lock)");
    }

    @Override
    public void unlock(Lock lock) {
        logger.info("【{}】unlock the redlock {} start...", Thread.currentThread().getName(), lock);
        if (lock != null) {
            lock.unlock();
            logger.info("【{}】unlock the redlock {} end...", Thread.currentThread().getName(), lock);
        } else {
            logger.info("【{}】lock is null, {} don't need to unlock", Thread.currentThread().getName(), lock);
        }

    }
}

RedissonRedDisLockService

package com.zrj.autolog.lock;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;

/**
 * 分布式锁接口
 *
 * @author zrj
 * @since 2021/12/9
 **/
@Slf4j
@Service
public class RedissonRedDisLockService {

    @Resource
    private RedissonRedDisLock redDisLock;

    /**
     * 分布式锁测试
     */
    public void redissonRedDisLockTest() {
        //定义锁
        Lock lock = null;
        //获取lockKey
        //String lockKey = getDateRandom();
        String lockKey = "newRedDisLock1";
        log.info("【{}】lock key name {}", Thread.currentThread().getName(), lockKey);

        try {
            //尝试加锁,加不上锁,则等待30秒,仍然加不上则直接返回失败。
            //30秒以内加上锁,上锁以后180秒自动解锁,防止死锁发生,业务处理不超过3分钟(这个需要根据实际业务场景评估)
            lock = redDisLock.lock(lockKey, TimeUnit.SECONDS, 10, 180);
            if (lock == null) {
                log.error("lock use redlock with name {} failed.", lockKey);
                throw new RuntimeException("lock failed with name " + lockKey);
            }
            //执行业务逻辑
            Thread.sleep(1000);
            log.info("【{}】业务逻辑处理!", Thread.currentThread().getName());
        } catch (Exception e) {
            log.error("lock failed because {},{}", e.getMessage(), e);
            throw new RuntimeException("lock failed with name " + lockKey);
        } finally {
            redDisLock.unlock(lock);
        }
    }

    /**
     * 加锁测试
     */
    public void lockRedDisLock() throws LockFailException {
        //永久锁,加不上锁,立即返回失败
        //Lock permanentLock = redDisLock.lock("RedDisLock");

        //永久锁,加不上锁,等待10秒,返回加锁失败
        //Lock awaitLock = redDisLock.lock("RedDisLock", TimeUnit.SECONDS, 10, -1);

        //临时锁,加不上锁,waitTime=-1的时候一直等待,会导致死锁,加上锁以后20秒自动解锁
        //临时锁,加不上锁,waitTime=10的时候,超过10秒自动返回失败,加上锁以后20秒自动解锁
        //Lock leaseLock = redDisLock.lock("RedDisLock", TimeUnit.SECONDS, 10, 20);
        Lock newLeaseLock = redDisLock.lock("newRedDisLock1", TimeUnit.SECONDS, 10, 20);

        log.info("RedDisLock加锁成功:{}", newLeaseLock);
    }

    /**
     * 解锁测试
     */
    public void unlockRedDisLock() throws LockFailException {
        Lock lock = redDisLock.lock("RedDisLock");
        redDisLock.unlock(lock);
        log.info("RedDisLock解锁成功:{}", lock);
    }

    /**
     * 生成日期字符串,例如:20211213095419569
     */
    public String getDateRandom() {
        return DateUtil.format(DateUtil.date(), "yyyyMMddHHmmssSSS");
    }

    /**
     * 生成的是不带-的字符串,例如:b17f24ff026d40949c85a24f4f375d42
     */
    public String getSimpleUUID() {
        return IdUtil.simpleUUID();
    }
}

DistributeLockController

package com.zrj.autolog.controller;

import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.zrj.autolog.entity.Response;
import com.zrj.autolog.lock.LockFailException;
import com.zrj.autolog.lock.RedissonRedDisLockService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.concurrent.*;

/**
 * 分布式锁控制类
 *
 * @author zrj
 * @since 2021-06-21 16:44:24
 */
@Slf4j
@RestController
@RequestMapping("/lock")
@Api(tags = "lock", description = "分布式锁")
public class DistributeLockController {

    @Resource
    private RedissonRedDisLockService redissonRedDisLockService;

    // 自定义线程名称
    private static ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("lock-thread-%d").build();
    // 定义线程池
    private static ExecutorService executor = new ThreadPoolExecutor(30, 200, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());

    /**
     * 测试接口
     * 自定义过滤器,拦截器
     */
    @GetMapping("/test")
    @ApiOperation(value = "测试接口")
    public Response<String> test() {
        return Response.success("测试接口成功", null);
    }

    /**
     * 分布式锁测试
     */
    @GetMapping("/redissonRedDisLockTest")
    @ApiOperation(value = "分布式锁测试")
    public Response redissonRedDisLockTest() {
        //启动10个线程验证分布式锁
        for (int i = 0; i < 5; i++) {
            executor.execute(() -> redissonRedDisLockService.redissonRedDisLockTest());
        }
        return Response.success("分布式锁测试成功", null);
    }

    /**
     * 加锁测试
     */
    @GetMapping("/lockRedDisLock")
    @ApiOperation(value = "加锁测试")
    public Response lockRedDisLock() {
        try {
            redissonRedDisLockService.lockRedDisLock();
        } catch (LockFailException e) {
            e.printStackTrace();
        }
        return Response.success("加锁测试", null);
    }

    /**
     * 解锁测试
     */
    @GetMapping("/unlockRedDisLock")
    @ApiOperation(value = "解锁测试")
    public Response unlockRedDisLock() {
        try {
            redissonRedDisLockService.unlockRedDisLock();
        } catch (LockFailException e) {
            e.printStackTrace();
        }
        return Response.success("解锁测试", null);
    }

}

你可能感兴趣的:(服务架构,Redisson分布式锁实现)