(四)Redis学习笔记 --- SpringBoot集成Redis之分布式锁

1、简介

​ 分布式锁有很多种实现方式,使用数据库、Redis、Zookeeper等都可以,但综合性能等使用最广泛的还是Redis分布式锁。

2、环境部分请参考

​ 2.1 (一)Redis学习笔记 — redis在linux下的安装及基本配置

​ 2.2 (二)Redis学习笔记 — redis集群配置

​ 2.3 (三)Redis学习笔记 — springboot集成redis

3、分布式锁

3.1 普通分布式锁

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 普通锁
     * @param lockName 锁名称
     * @return
     */
    public boolean lock(String lockName) {
        Boolean success = null;
        try {
            success = redisTemplate.opsForValue().setIfAbsent(lockName, "lock");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return success != null && success;
    }

    /**
     * 普通锁解锁
     * @param lockName 锁名称
     */
    public boolean unlock(String lockName) {
        Boolean success = null;
        try {
            if (lockName != null && redisTemplate.hasKey(lockName)
                && "lock".equals(redisTemplate.opsForValue().get(lockName))) {
                success = redisTemplate.delete(lockName);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return success != null && success;
    }

3.2 限时锁

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 限时锁
     * @param lockName 锁名称
     * @param expireTime 期望时间(单位:秒),一般比最大业务预计完成时间稍长
     * @return
     */
    public boolean expireTimeLock(String lockName, long expireTime) {
        Boolean success = null;
        try {
            success = redisTemplate.opsForValue().setIfAbsent(lockName, "expireTimeLock", expireTime, TimeUnit.SECONDS);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return success != null && success;
    }

    /**
     * 限时锁解锁,该锁解锁失败也无所谓,过期会自动解除
     * @param lockName 锁名称
     */
    public void unExpireTimeLock(String lockName) {
        try {
            if (redisTemplate.hasKey(lockName) && "expireTimeLock".equals(redisTemplate.opsForValue().get(lockName))) {
                redisTemplate.delete(lockName);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

3.3 阻塞锁

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 普通锁,如果加锁失败,可以重新尝试retryTimes次,所以最大加锁次数是retryTimes + 1次。
     * 该加锁是阻塞加锁,解锁方式用普通锁解锁!
     * @param lockName 锁名称
     * @param retryTimes 重新尝试次数
     * @return
     */
    public boolean tryLock(String lockName, int retryTimes) {
        boolean lock = lock(lockName);
        if (retryTimes == 0) {
            retryTimes = 3;
        }

        // 如果加锁失败,每过5s尝试加锁一次
        int times = 1;
        while (!lock && times <= retryTimes) {
            //上面已经尝试加锁一次,所以如果要retry,先睡5s
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            lock = lock(lockName);
            times ++;
        }

        return lock;
    }

    /**
     * 限时锁,如果加锁失败,可以重新尝试retryTimes次,所以最大加锁次数是retryTimes + 1次。
     * 该加锁是阻塞加锁,解锁方式用限时锁解锁!
     * @param lockName 锁名称
     * @param expireTime 期望时间(单位:秒),一般比最大业务预计完成时间稍长
     * @param retryTimes 重新尝试次数
     * @return
     */
    public boolean tryExpireTimeLock(String lockName, long expireTime, int retryTimes) {
        boolean expireTimeLock = expireTimeLock(lockName, expireTime);
        if (retryTimes == 0) {
            retryTimes = 3;
        }

        // 如果加锁失败,每过5s尝试加锁一次
        int times = 1;
        while (!expireTimeLock && times <= retryTimes) {
            //上面已经尝试加锁一次,所以如果要retry,先睡5s
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            expireTimeLock = expireTimeLock(lockName, expireTime);
            times ++;
        }

        return expireTimeLock;
    }

3.4 线程锁

    @Autowired
    private RedisTemplate redisTemplate;

	/**
     * 线程锁,只有当前线程才能解锁
     * 留一个小bug,线程锁名称应该和线程ID相关,这样才不会被别人误操作解除。
     * @param lockName 锁名称
     * @param currentThread 当前线程
     * @return
     */
    public boolean threadLock(String lockName, Thread currentThread) {
        Boolean success = null;
        try {
            success = redisTemplate.opsForValue().setIfAbsent(lockName, String.format("threadLock_%s", String.valueOf(currentThread.getId())));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return success != null && success;
    }

    /**
     * 线程锁解锁
     * @param lockName 锁名称
     * @param currentThread 当前线程
     * @return
     */
    public boolean unThreadLock(String lockName, Thread currentThread) {
        Boolean success = null;
        try {
            if (redisTemplate.hasKey(lockName) &&
                    String.format("threadLock_%s", String.valueOf(currentThread.getId())).equals(redisTemplate.opsForValue().get(lockName))) {
                success = redisTemplate.delete(lockName);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return success != null && success;
    }

4、总结

​ 以上是个人学习时博客到的所有内容的总结,其实个人觉得分布式锁应该还有自动续期的功能,那样要加一个守护线程,时刻去监测当前锁时间是否已经过了三分之二,如果过了自动将锁重置。这个只是对限时锁或者阻塞限时锁有用,且实现稍微麻烦,在这里不实现了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值