基于Redis的分布式锁 使用条件:jedis(转自群内大佬)

/**
 * @Description: 基于Redis的分布式锁 使用条件:jedis。
 * @Author Chase Lou
 * @Date 2019/7/24 19:26
 **/
@Component
public class RedisLock {

    private final Logger log = LoggerFactory.getLogger(RedisLock.class);

    /**
     * 默认获取锁超时时间是5秒
     */
    private final long defaultGetTimeOut = 5000;

    /**
     * 默认锁过期时间5
     */
    private final long defaultExpire = 5000;

    private final LockProcessor lockProcessor =
            (jedisCommands, resource, secretKey, expire) ->
                    jedisCommands.set(RedisKeyConstants.LOCKS + resource, secretKey, "NX", "PX", expire);
    private final UnlockProcessor unlockProcessor =
            (jedisCommands, resource, secretKey) -> {
                if (secretKey.equals(jedisCommands.get(RedisKeyConstants.LOCKS + resource))) {
                    return jedisCommands.del(RedisKeyConstants.LOCKS + resource).longValue() == 1L;
                }
                return false;
            };

    @Autowired
    StringRedisTemplate stringRedisTemplate;

    public String tryLock(String resource) throws RedisLockTimeOutException {
        return tryLock(resource, defaultGetTimeOut, defaultExpire);
    }

    public String tryLock(String resource, long expire) throws RedisLockTimeOutException{
        return tryLock(resource, defaultGetTimeOut, expire);
    }

    public String tryLock(String resource, long getTimeOut, long expire) throws RedisLockTimeOutException{
        return lock(resource, getTimeOut, expire, false);
    }

    public String directLock(String resource) {
        return directLock(resource, defaultExpire);
    }

    public String directLock(String resource, long expire) {
        return lock(resource, -1, expire, false);
    }

    public String blockLock(String resource) {
        return blockLock(resource, defaultExpire);
    }

    public String blockLock(String resource, long expire) {
        return lock(resource, -1, expire, true);
    }

    /**
     * 获取redis锁
     *
     * @param resource         被锁的资源名称
     * @param getTimeOut       获取锁超时时间,负数表示不会超时,只会尝试一次
     * @param expire           锁最长时间,将在该时间后自动释放锁
     * @param waitingOnSuccess 是否一直等待到获取成功
     * @return todo 返回值类型应该更有意义
     */
    private String lock(String resource, long getTimeOut, long expire, boolean waitingOnSuccess) throws RedisLockTimeOutException{
        if (StringUtils.isEmpty(resource)) {
            throw new RedisLockNoResourceException(String.format("请求上锁的资源[%s]不合法,请保证资源不为空", resource));
        }
        long currentTimeMillis = System.currentTimeMillis();
        String secretKey = String.format("%s%s%s,Expires after %s millisecond", resource, currentTimeMillis, Math.random(), expire);
        log.info("获取[{}]的redis锁:开始尝试", resource);
        do {
            String execute = stringRedisTemplate.execute((RedisCallback<String>) connection ->
                    lockProcessor.apply((JedisCommands) connection.getNativeConnection(), resource, secretKey, expire));
            //如果执行成功execute等于"OK"
            if (!StringUtils.isEmpty(execute)) {
                log.info("获取[{}]的redis锁:成功,耗时[{}]ms", resource, System.currentTimeMillis() - currentTimeMillis);
                return secretKey;
            }
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                log.error(String.format("获取[{}]的redis锁:线程异常", resource), e);
                Thread.currentThread().interrupt();
            }
        } while (waitingOnSuccess || (getTimeOut > 0 && System.currentTimeMillis() - currentTimeMillis < getTimeOut));
        log.info("获取[{}]的redis锁:失败", resource);
        if (getTimeOut > 0) {
            throw new RedisLockTimeOutException(String.format("获取[%s]的redis锁超过获取时间[%s],请延长获取时间或者优化代码的处理速度", resource, getTimeOut));
        }
        return "";
    }

    /**
     * 释放redis锁
     *
     * @param resource  被锁资源
     * @param secretKey 锁秘钥,防止自己锁过期的时候,释放了其他人的锁
     */
    public void unlock(String resource, String secretKey) {
        if (StringUtils.isEmpty(resource) || StringUtils.isEmpty(secretKey)) {
            throw new RedisUnlockNoResourceException(String.format("请求解锁的资源[%s]或者秘钥[%s]不合法,请保证资源或者秘钥不为空", resource, secretKey));
        }
        log.info("释放[{}]的redis锁:开始尝试", resource);
        Boolean success =
                stringRedisTemplate.execute((RedisCallback<Boolean>) connection -> unlockProcessor.apply((JedisCommands) connection.getNativeConnection(), resource, secretKey));
        if (success) {
            log.info("释放[{}]的redis锁:成功", resource);
        } else {
            log.info("释放[{}]的redis锁:失败", resource);
            throw new RedisUnlockException(String.format("释放[%s]的redis锁失败,可能由于执行时间过长或者尝试释放不属于自己的锁。", resource));
        }
    }

    @FunctionalInterface
    private interface LockProcessor {
        String apply(JedisCommands jedisCommands, String resource, String secretKey, long expire);
    }

    @FunctionalInterface
    private interface UnlockProcessor {
        boolean apply(JedisCommands jedisCommands, String resource, String secretKey);
    }
}


```闲聊时刻

10年短信公司,互联网100强企业!主营业务:短信(国内和国际)App H5一键免密登录,防薅羊毛接口,图片OCR,空号检测,活跃号检测,人证核验,活体检测,高防ddos攻击等等200多个企业服务接口!需要的联系他13592366783 官方链接:https://zz.253.com/v5.html#/register?uid=1953

自己公司需求 偶然间 用了一家第三方接口供应商,产品应有尽有,很齐全,对接文档非常详细,彼此都很节约时间,主要非常稳定,包括服务方面很给力,有兴趣的博友,可以联系他,算是对合作伙伴的支持了


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值