请老师帮忙看看,在RedisShardedPoolUtil中设置带有效期的锁的方法实现

来源:14-4 本章总结

慕慕8288485

2020-03-10

请老师帮忙看看,在RedisShardedPoolUtil.java 中这样实现有没有问题?谢谢~~

/**
 * 带过期时间的分布式锁
 *
 * @param key
 * @param seconds 有效期时间(秒)
 * @return
 */
public static Long setnxEx(String key, int seconds) {
    try {
        try (ShardedJedis jedis = RedisShardedPool.getJedis()) {
            // 尝试获取锁
            Long setnxResult = jedis.setnx(key, String.valueOf(System.currentTimeMillis() + seconds * 1000));
            if (setnxResult == null || setnxResult.intValue() != 1) {
                // 未获取到锁,继续判断时间戳,看是否可以重置并获取到锁
                String lockValueStr = jedis.get(key);
                if (lockValueStr != null && System.currentTimeMillis() < Long.parseLong(lockValueStr)) {
                    // key存在且时间戳未过,获取锁失败
                    return 0L;
                }

                // key不存在(已经过期或被删除)或者时间戳已过,利用getset原子操作尝试获取
                String getsetResult = jedis.getSet(key, String.valueOf(System.currentTimeMillis() + seconds * 1000));
                if (getsetResult != null && !StringUtils.equals(lockValueStr, getsetResult)) {
                    // key已经被其他请求重置并获取锁,本次请求获取锁失败(负面后果:少量延长了该锁的时间戳)
                    return 0L;
                }

                // key不存在(已经过期或被删除)或者key的原值与前面获取的相同(表示没有其他请求重置key并获取到锁),获取锁成功
                setnxResult = 1L;
            }
            // 获取锁成功,设置超时
            Long expireResult = jedis.expire(key, seconds);
            if (expireResult == null || expireResult.intValue() != 1) {
                throw new Exception("set key: " + key + " expire error. return: " + expireResult);
            }
            return setnxResult;
        }
    } catch (Exception e) {
        log.error("setnxEx key: {}  error", key, e);
    }
    return null;
}
写回答

2回答

geelylucky

2020-03-10

同学,可以写一个多线程并发的测试代码测试一下。

0
1
慕慕8288485
非常感谢!
2020-03-11
共1条回复

慕慕8288485

提问者

2020-03-11

简单测试通过,基本上是实现课程中的逻辑。

redis2.6.x之后已经支持 SET 带 nx 和 ex的参数,作为一个原子操作,就不需要这么麻烦了吧。另外,Redisson通过eval一段lua代码来实现RedLock,还能实现可重入锁。看来,自己还得快点更新知识啊。

0
1
geelylucky
对的,Redisson已经实现了这个
2020-03-14
共1条回复

Java企业级电商项目架构 Tomcat集群与Redis分布式

Tomcat集群+Redis分布式+代码重构+源码原理解析

2685 学习 · 947 问题

查看课程