Redisson分布式锁的静态方式和springboot管理方式两种实现

Redisson分布式锁的实现

maven 引入依赖包

<dependency>
   <groupId>org.redisson</groupId>
   <artifactId>redisson</artifactId>
   <version>3.16.4</version>
</dependency>  

静态方式 Redisson 分布式重入锁用法

Redisson 支持单点模式、主从模式、哨兵模式、集群模式,这里以单点模式为例:

import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;

import java.util.concurrent.TimeUnit;

public class RedisLock {

    public static void setLock(String lockKey,Long waitTimeout,Long leaseTime){
        // 1.构造redisson实现分布式锁必要的Config  redis 的连接地址和密码以及选择的数据库
        Config config = new Config();
        config.useSingleServer().setAddress("redis连接地址").setPassword("密码").setDatabase(第几个数据库);
        // 2.构造RedissonClient
        RedissonClient redissonClient = Redisson.create(config);
        // 3.获取锁对象实例(无法保证是按线程的顺序获取到)
        RLock rLock = redissonClient.getLock(lockKey);
        try {
            /**
             * 4.尝试获取锁
             * waitTimeout 尝试获取锁的最大等待时间,超过这个值,则认为获取锁失败
             * leaseTime   锁的持有时间,超过这个时间锁会自动失效(值应设置为大于业务处理的时间,确保在锁有效期内业务能处理完)
             */
            boolean res = rLock.tryLock((long)waitTimeout, (long)leaseTime, TimeUnit.SECONDS);
            System.out.println(res);
            if (res) {
                //成功获得锁,在这里处理业务
            }
        } catch (Exception e) {
            throw new RuntimeException("aquire lock fail");
        }finally{
            //无论如何, 最后都要解锁
            rLock.unlock();
        }
    }
}

springboot管理方式 Redisson 分布式重入锁用法

RedissonConfig 配置类
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.ClusterServersConfig;
import org.redisson.config.Config;
import org.redisson.config.SentinelServersConfig;
import org.redisson.config.SingleServerConfig;
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;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;

@Configuration
@EnableConfigurationProperties(RedissonProperties.class)
public class RedissonConfig {

    @Resource
    private RedissonProperties redissonProperties;

    @Bean
    @ConditionalOnMissingBean
    RedissonClient redissonSingle() {
        // 1.构造redisson实现分布式锁必要的Config  redis 的连接地址和密码以及选择的数据库
        Config config = new Config();

        //单机 redis地址
        String host = this.redissonProperties.getHost();
        //哨兵地址
        String[] sentinelAddr = this.redissonProperties.getSentinelAddresses();
        //其他节点地址
        String[] nodeAddresses = this.redissonProperties.getNodeAddresses();
        if (!StringUtils.isEmpty(host)) {
            config.setLockWatchdogTimeout((long)this.redissonProperties.getLockWatchdogTimeout());
            SingleServerConfig serverConfig = ((SingleServerConfig)config.useSingleServer().setAddress("redis://" + this.redissonProperties.getHost() + ":" + this.redissonProperties.getPort()).setTimeout((int)this.redissonProperties.getTimeout().getSeconds() * 1000)).setConnectionPoolSize(this.redissonProperties.getConnectionPoolSize()).setConnectionMinimumIdleSize(this.redissonProperties.getConnectionMinimumIdleSize().setDatabase(this.redissonProperties.getDatabase()));
            if (!StringUtils.isEmpty(this.redissonProperties.getPassword())) {
                serverConfig.setPassword(this.redissonProperties.getPassword());
            }
        } else if (sentinelAddr != null && sentinelAddr.length > 0) {
            config.setLockWatchdogTimeout((long)this.redissonProperties.getLockWatchdogTimeout());
            SentinelServersConfig serverConfig = (SentinelServersConfig)((SentinelServersConfig)((SentinelServersConfig)config.useSentinelServers().addSentinelAddress(this.redissonProperties.getSentinelAddresses()).setMasterName(this.redissonProperties.getMasterName()).setTimeout((int)this.redissonProperties.getTimeout().getSeconds() * 1000)).setMasterConnectionPoolSize(this.redissonProperties.getMasterConnectionPoolSize())).setSlaveConnectionPoolSize(this.redissonProperties.getSlaveConnectionPoolSize());
            if (!StringUtils.isEmpty(this.redissonProperties.getPassword())) {
                serverConfig.setPassword(this.redissonProperties.getPassword());
            }
        } else if (nodeAddresses != null && nodeAddresses.length > 0) {
            config.setLockWatchdogTimeout((long)this.redissonProperties.getLockWatchdogTimeout());
            ClusterServersConfig serverConfig = config.useClusterServers().addNodeAddress(this.redissonProperties.getNodeAddresses()).setScanInterval(this.redissonProperties.getScanInterval());
            if (!StringUtils.isEmpty(this.redissonProperties.getPassword())) {
                serverConfig.setPassword(this.redissonProperties.getPassword());
            }
        }

        // 2.根据config构造RedissonClient
        RedissonClient redissonClient = Redisson.create(config);

        return redissonClient;
    }
    @Bean
    @ConditionalOnClass(RedissonClient.class)
    RedisLock redisLock(){
        RedisLock redisLock = new RedisLock();
        return redisLock;
    }

}

RedissonProperties 属性类 (根据前缀去yml启动配置文件配置属性)
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;

import java.time.Duration;

@ConfigurationProperties(
        prefix = "spring.redis"
)
@Data
public class RedissonProperties {
    private Duration timeout;
    private String host;
    private int port = 6379;
    private String password;
    private int database = 0;
    private int connectionPoolSize = 64;
    private int connectionMinimumIdleSize = 10;
    private int slaveConnectionPoolSize = 250;
    private int masterConnectionPoolSize = 250;
    private int lockWatchdogTimeout = 30000;
    private String[] sentinelAddresses;
    private String masterName;
    private int scanInterval;
    private String[] nodeAddresses;
    private int maxPushCount = 6;
}
RedisLock (自己编写redission锁工具类)
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.redisson.api.RLock;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

@Component
public class RedisLock {

    @Autowired(
            required = false
    )
    private RedissonClient redissonClient;

    /**
     * @param lockKey
     * @param task 这里用的是Supplier,可以根据业务自己定制
     * @return
     */
    public  void tryLock(String lockKey, Supplier<?> task,int num){
        // 获取锁对象实例(无法保证是按线程的顺序获取到)
        RLock rLock = redissonClient.getLock(lockKey);
        try {

            boolean res = rLock.tryLock();
            //多次尝试获得
            while(--num>0 && !res){
                res = rLock.tryLock();
            }
            if (res) {
                //成功获得锁,在这里处理业务
                task.get();
            }else{
                throw new Exception("aquire lock fail");
            }
        } catch (Exception e) {
            //根据业务业务情况来确定是抛异常还是返回结果
            throw new RuntimeException(e);

        }finally{
            //当前线程还占领着锁,则释锁
            RLock lock = redissonClient.getLock(lockKey);
            if (lock != null && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    public  void tryLock(String lockKey, Supplier<?> task){
        tryLock(lockKey,task,1);
    }

    /**
     *
     * @param lockKey
     * @param task  这里用的是Supplier,可以根据业务自己定制
     * @param waitTimeout 尝试获取锁的最大等待时间,超过这个值,则认为获取锁失败
     * @param leaseTime 锁的持有时间,超过这个时间锁会自动失效(值应设置为大于业务处理的时间,确保在锁有效期内业务能处理完)
     * @param unit
     * @param num 总共尝试获得锁的次数
     * @return
     */
    public  T <T> tryLock(String lockKey, Supplier<T> task, Long waitTimeout, Long leaseTime,TimeUnit unit,int num){

        // 获取锁对象实例(无法保证是按线程的顺序获取到)
        RLock rLock = redissonClient.getLock(lockKey);
        try {
            /**
             * 尝试获取锁
             * waitTimeout 尝试获取锁的最大等待时间,超过这个值,则认为获取锁失败
             * leaseTime   锁的持有时间,超过这个时间锁会自动失效(值应设置为大于业务处理的时间,确保在锁有效期内业务能处理完)
             */
            boolean res = rLock.tryLock((long)waitTimeout, (long)leaseTime, unit);
            //多次尝试获得
            while(--num>0 && !res){
                res = rLock.tryLock((long)waitTimeout, (long)leaseTime, unit);
            }
            if (res) {
                long start = System.currentTimeMillis();
                log.info("aquire lock success [{}]",lockKey);
                //成功获得锁,在这里处理业务
                T result = task.get();
                log.info("execute task success [{}] and cost time {} ",lockKey,System.currentTimeMillis()-start);
                return result;
            }else{
                log.error("aquire lock fail [{}]",lockKey);
                throw new Exception("aquire lock fail");
            }
            //抛出业务本身抛出的异常(根据你实际项目定义)
        }catch (BusinessException e){
            log.error("execute task fail [{}]",lockKey);
            throw e;
        }
        catch (Exception e) {
            throw new RuntimeException(e);
        }
        finally{
            //当前线程还占领着锁,则释放锁
            RLock lock = redissonClient.getLock(lockKey);
            if (lock != null && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
            log.info("unlock [{}]",lockKey);
        }
    }


    public  T <T> tryLock(String lockKey, Supplier<T> task, Long waitTimeout, Long leaseTime,TimeUnit unit){
        return tryLock(lockKey,task,waitTimeout,leaseTime,unit,1);
    }

    /**
     * 批量加锁
     * @param lockKeyList 需要加锁的key
     * @param task 
     * @return
     * @param <T>
     */
    public <T> T multiTryLock(List<String> lockKeyList, Supplier<T> task) {
        return multiTryLock(lockKeyList, task, 5000L, 30000L, TimeUnit.MILLISECONDS, 1);
    }

    public <T> T multiTryLock(List<String> lockKeyList, Supplier<T> task, Long waitTimeout, Long leaseTime, TimeUnit unit) {
        return multiTryLock(lockKeyList, task, waitTimeout, leaseTime, unit, 1);
    }

    public <T> T multiTryLock(List<String> lockKeyList, Supplier<T> task, Long waitTimeout, Long leaseTime, TimeUnit unit, int num) {
        RedissonMultiLock multiLock = getMultiLock(lockKeyList);
        try {
            boolean res = multiLock.tryLock(waitTimeout, leaseTime, unit);

            while (--num > 0 && !res) {
                res = multiLock.tryLock(waitTimeout, leaseTime, unit);
            }

            if (res) {
                long start = System.currentTimeMillis();
                log.info("acquire multiLock success keyListSize:[{}]", lockKeyList.size());
                T result = task.get();
                log.info("execute multiLock success keyListSize:[{}] and cost time {} ", lockKeyList.size(), System.currentTimeMillis() - start);
                return result;
            } else {
                log.error("acquire multiLock fail keyListSize:[{}]", lockKeyList.size());
                throw new BusinessException(BlogisWmsResultStatusEnum.SYS_BUSY);
            }
        }  catch (BusinessException e) {
            log.error("execute task fail keyListSize:[{}] msg:[{}]", lockKeyList.size(),e.getMessage()==null?e.getCause():e.getMessage());
            throw e;
        } catch (Exception e) {
            log.error("execute task fail keyListSize:[{}] msg:[{}]", lockKeyList.size(),e.getMessage()==null?e.getCause():e.getMessage());
            throw new RuntimeException(e);
        } finally {
            unMultiLock(lockKeyList);
            log.info("unMultiLock [{}]", lockKeyList.size());
        }

    }

    /**
     * 获得连锁
     * @param lockKeyList
     * @return
     */
    private RedissonMultiLock getMultiLock(List<String> lockKeyList) {
        List<RLock> rLockList = new ArrayList<>(lockKeyList.size());
        for (String key : lockKeyList) {
            RLock rLock = redissonClient.getLock(key);
            rLockList.add(rLock);
        }
        RLock[] rLocks = rLockList.toArray(new RLock[0]);
        return  (RedissonMultiLock)redissonClient.getMultiLock(rLocks);
    }

    /**
     * 释放连锁
     * @param lockKeyList
     */
    private void unMultiLock(List<String> lockKeyList) {
        for (String key : lockKeyList) {
            RLock lock = redissonClient.getLock(key);
            if (lock != null && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
        
    }

}

相关

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值