Redis 分布式锁

官方网址

单节点续命锁(自定义线程池测试)

@Slf4j
public class ReentrantLockDemo {
    public static RedissonClient redissonClient;

    static {
        Config config = new Config();
        // Redis单节点模式
        SingleServerConfig singleServerConfig = config.useSingleServer();
        singleServerConfig.setPassword("LI1234REDIS!");
        singleServerConfig.setAddress("redis://192.168.213.137:6379");
        singleServerConfig.setDatabase(0);
        // 客户端实例
        redissonClient = Redisson.create(config);
    }

    public static void main(String[] args) throws InterruptedException {
        ExecutorService executorService = new ThreadPoolExecutor(
                10,
                100,
                30, TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(100),
                new ThreadPoolExecutor.CallerRunsPolicy());
        /*
         * 幂等:
         * 1、通过分布式锁过滤掉短时间内(假设当前业务执行耗时N秒,则N秒内的重复请求都会被过滤掉,但N秒之后的重复请求并不会被过滤)的重复请求
         * 2、添加数据时,设置主键、联合主键约束,防止重复数据的产生
         */
        for (int i = 0; i < 10; i++) {
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    RLock rLock = redissonClient.getLock("rLock");
                    boolean res = false;
                    try {
                        /*
             			* 1、如果需要使用续锁功能,请不要设置锁的过期时间(可以设置成-1),否则RedissonLock就会认为你需要自己控制锁时间而放弃执行续锁逻辑
             			* 2、RedissonLock的续锁逻辑是用netty下的Timeout定时器来实现的,默认锁时间是30秒,定时器每锁时间/3也就是10秒执行一次。来判断是否还持有锁,如果还持有锁就重置锁时间为30秒。从而避免业务执行时间大于锁时间而导致的锁被释放了的问题
             			*/
            			// 尝试取锁:
            			// 1、取锁超时时间 500 毫秒,超过则取锁失败
            			// 2、取锁成功后,-1表示锁使用默认的有效期30秒(如果业务提前执行完毕也会提前释放锁),每隔30/3(10)秒会自动检测锁是否存在,存在则重置锁的有效期为 30 秒
                        res = rLock.tryLock(500, -1, TimeUnit.MILLISECONDS);
                        if (res) {
                            log.info(Thread.currentThread().getName()+" 拿到锁,开始执行任务");
                            Thread.sleep(8000);
                            log.info(Thread.currentThread().getName()+" 拿到锁,执行任务成功");
                        } else {
                            log.info(Thread.currentThread().getName()+" 超时,未拿到锁");
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } finally {
                        if(rLock.isLocked() && rLock.isHeldByCurrentThread()) {
                            // 释放锁
                            rLock.unlock();
                        }
                    }
                }
            });
        }
        // 关闭线程池
        executorService.shutdown();
    }
}

在这里插入图片描述

单节点续命锁(jmeter测试)

@Resource
    private RedissonClient redissonClient;
    /**
     * @描述 单节点续命锁
     * @作者 lixing_java@163.com
     * @日期 2021/9/17 14:29
     * 直接访问:127.0.0.1:8770/apiAdmin/demo/reentrantLock
     * 网关访问:127.0.0.1:8763/springCloudGateway/gatewayAdmin/demo/reentrantLock
     */
    @GetMapping("reentrantLock")
    public BaseResult<String> reentrantLock() {
        RLock rLock = redissonClient.getLock("rLock");
        boolean res = false;
        try {
            /*
             * 1、如果需要使用续锁功能,请不要设置锁的过期时间(可以设置成-1),否则RedissonLock就会认为你需要自己控制锁时间而放弃执行续锁逻辑
             * 2、RedissonLock的续锁逻辑是用netty下的Timeout定时器来实现的,默认锁时间是30秒,定时器每锁时间/3也就是10秒执行一次。来判断是否还持有锁,如果还持有锁就重置锁时间为30秒。从而避免业务执行时间大于锁时间而导致的锁被释放了的问题
             */
            // 尝试取锁:
            // 1、取锁超时时间 500 毫秒,超过则取锁失败
            // 2、取锁成功后,-1表示锁使用默认的有效期30秒(如果业务提前执行完毕也会提前释放锁),每隔30/3(10)秒会自动检测锁是否存在,存在则重置锁的有效期为 30 秒
            res = rLock.tryLock(500, -1, TimeUnit.MILLISECONDS);
            if (res) {
                LoggerUtil.info(MessageFormat.format("{0} 拿到锁,开始执行任务", Thread.currentThread().getName()));
                Thread.sleep(150000); // 休眠N秒,模拟业务执行时间
                LoggerUtil.info(MessageFormat.format("{0} 拿到锁,执行任务成功", Thread.currentThread().getName()));
                return new BaseResult<String>().success(MessageFormat.format("{0} 拿到锁,执行任务成功", Thread.currentThread().getName()));
            } else {
                LoggerUtil.info(MessageFormat.format("{0} 取锁超市", Thread.currentThread().getName()));
                return new BaseResult<String>().success(MessageFormat.format("{0} 取锁超时", Thread.currentThread().getName()));
            }
        } catch (InterruptedException e) {
            LoggerUtil.error(MessageFormat.format("{0} 系统错误:{1}", Thread.currentThread().getName(), e.getMessage()));
            return new BaseResult<String>().fail(MessageFormat.format("{0} 系统错误:{1}", Thread.currentThread().getName(), e.getMessage()));
        } finally {
            if(rLock.isLocked() && rLock.isHeldByCurrentThread()) {
                // 释放锁
                LoggerUtil.info(MessageFormat.format("{0} 释放锁", Thread.currentThread().getName()));
                rLock.unlock();
            }
        }
    }

在这里插入图片描述

红锁

主从模式下,客户端跟多个 Redis 实例请求加锁,只有超过半数的实例加锁成功,才认为成功获取了分布式锁。避免(主节点写入数据成功,在没有将数据复制给从节点时,主节点宕机了,则会造成提升为主节点的从节点中是没有锁信息的,其它线程又可以继续加锁)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大能嘚吧嘚

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值