jedis 实现分布式锁

/**
     * 使用redis实现分布式锁
     *    @ReturnType    void 
     *    @Date    2018年9月21日    下午6:00:50
     *  @Param  @param key                    数据的key
     *  @Param  @param timeout                超时时间(超时未获得锁会报异常)、锁存活最长时间。默认60s, unit: second
     */
    public static void lock(String key, Integer timeout){
        Assert.notNull(key, "key must not be nul");
        if (timeout == null || timeout <= 0) {
            timeout = 60;
        }
        // 初始时间
        Instant start = Instant.now();
        // 锁的key
        String lockKey = LOCK + key;
        // 是否获取锁成功
        boolean lockStatus = false;
        // 循环timeout秒
        while (Duration.between(start, Instant.now()).toMillis() <= 1000 * timeout) {
            log.info("redis...lock...try get lock->" + lockKey + ", wait->" + (Duration.between(start, Instant.now()).toMillis()) / 1000 + "s, max->" + timeout + "s");
            // 锁的过期时间
            long expireTime = (System.currentTimeMillis() + (timeout * 1000));
            // 尝试上锁
            lockStatus = setnx(lockKey, String.valueOf(expireTime), timeout);
            // 上锁成功,跳出循环
            if (lockStatus) {
                break;
            }
            // 上锁失败,可能是锁被别的地方抢走,或者死锁(生存时间永久,这种需要以下判断时间)
            // 先获取,看是否存在这个锁,存在则获取之前的过期时间
            long oldExpireTime = Long.parseLong(get(lockKey, "0"));
            // 如果锁中的过期时间小于当前系统时间,超时,可以允许别的请求重新获取
            if (oldExpireTime < System.currentTimeMillis()) {
                // 计算新的过期时间
                long newExpireTime = (System.currentTimeMillis() + (timeout * 1000));
                // 尝试获取当前锁中的生存时间,并设置新的过期时间进去
                String v = getSet(lockKey, String.valueOf(newExpireTime), timeout);
                long currentExpireTime = Long.parseLong(StringUtils.isBlank(v)? "0" : v);
                // 如果当前锁中的生存时间和之前获取的一致,说明没有被人设置过
                if (currentExpireTime == oldExpireTime) {
                    // 上锁成功
                    lockStatus = true;
                    // 跳出循环
                    break;
                }
            }
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
            }
        }
        // 超时
        if (!lockStatus) {
            throw new RuntimeException("redis lock-> " + lockKey + " fail...timeout : " + timeout);
        }
        // 上锁成功
        log.info("redis...lock...get lock success->" + lockKey);
    }
    
    /**
     * 如果不存在就设置进去
     *    @ReturnType    boolean 
     *    @Date    2018年9月21日    下午5:51:50
     *  @Param  @param key
     *  @Param  @param value
     *  @Param  @param seconds
     *  @Param  @return
     */
    public static boolean setnx(String key, String value, int seconds){ // 请使用StmsRedisTemplate
        return execute(key, jedis->{
            boolean succ = jedis.setnx(key, value)==1;
            if(succ){
                jedis.expire(key, seconds);
            }
            return succ;
        });
    }
    
    /**
     * 从redis获取数据
     *    @ReturnType    String 
     *    @Date    2018年1月23日    上午11:37:00
     *  @Param  @param key
     *  @Param  @param defaultValue        默认值
     *  @Param  @return
     */
    public static String get(String key, String defaultValue) {// 请使用StmsRedisTemplate.get
        String value = execute(key, jedis->jedis.get(key));
        return value == null ? defaultValue : value;
    }
    
    public static String getSet(String key, String value, int seconds) { // 请使用StmsRedisTemplate.getSet
        return execute(key, jedis->{
            String oldValue = jedis.getSet(key, value);
            jedis.expire(key, seconds);
            return oldValue;
        });
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值