redis分布式锁的具体应用

1、关于redis分布式锁,有个setIfAbsent:

即如果没有设置,会添加分布式锁,并返回true;

2、redis分布式锁有个轮询过程:

 /

* @param key redis键
* @param expire 键过期时间(单位:毫秒)
* @param timeout 超时时间(单位: 毫秒)
 * @return true表示加锁成功,false表示加锁失败
 */
public boolean lock(String key, long expire, long timeout) {

    timeout *= 1000*1000; //一般用常量表示,进行毫秒与纳秒之间的转换
    long nanoTime = System.nanoTime();

    try {

        //在timeout的时间范围内不断轮询锁
        while (System.nanoTime() - nanoTime < timeout) {

            //锁不存在的话,设置锁并设置锁过期时间,即加锁
            Boolean isSuccess = redisTemplate.opsForValue().setIfAbsent(key, RedisLock.LOCKED);
            if (isSuccess) {
                //设置锁过期时间是为了在没有释放锁的情况下锁过期后消失,不会造成永久阻塞
                redisTemplate.expire(key, expire, TimeUnit.MILLISECONDS);
                this.lock = true;
                return true;
            }

            //短暂休眠,避免可能的活锁
            Thread.sleep(3, RANDOM.nextInt(30));
        }
    } catch (Exception e) {
        throw new RuntimeException("locking error",e);
    }

    return false;

}

 3、设置分布式锁,一般而言,分布式锁只做判断,具体我们还要使用redis进行一个设置key的过程,这样也类似于另一把锁:

  为什么要使用另一把锁呢?其实分布式锁只是为了解决几个程序间同时操作的问题,它的时间非常不好控制,当我们有了另一把锁就可以轻易地去控制锁的时间,

            lockkey = RedisKeyConstants.LOCK_PREFIX + ":" + redisKey;
            redisLock.lock(lockkey, RedisKeyConstants.LOCK_ROUTE_GEN_EXPIRE_TIME, RedisKeyConstants.LOCK_ROUTE_GEN_TIMEOUT_TIME);

            //判断redis中是否有数据
            String redisValue = redisTemplate.opsForValue().get(redisKey);
            if (redisValue != null) {
                return;
            }
            redisTemplate.opsForValue().set(redisKey, "1", RedisKeyConstants.ROUTE_TYPE_GEN_EXPIRE_TIME, TimeUnit.SECONDS);

 4、程序结束后一定要在finally代码块中释放锁,这样就好了; 

finally {
            redisTemplate.delete(redisKey);
            redisLock.unlock(lockkey);
        }

 5、防止程序出现bug,所以我们设置另一把锁的失效时间为半个小时;

需要考虑的问题:

1、多台服务器的时间有误差;

2、人工触发;

3、服务器宕机;

猜你喜欢

转载自www.cnblogs.com/gendway/p/10497922.html
今日推荐