Redis使用场景(二)分布式锁详尽版

分布式锁除了 redis实现外还有:数据库乐观锁和zookeeper效率有限。

分布式锁要满足以下条件:

  互斥性:确保同一时刻只有一个客户端持有锁。

  不死锁:一个客户端持有锁因断网,崩溃等原因失联了,仍可让下一个人得到锁。

  容错性:大部分redis节点可用,客户端就可以加锁解锁。

  统一性:加锁和解锁必须为同一客户端。  

首先引包

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>2.9.0</version>
</dependency>

实现:

public class RedisTool {
    private static final String LOCK_SUCCESS = "OK";
    private static final String SET_NOT_EXIST = "NX";
    private static final String SET_EXPIRE_TIME = "PX";
    private static final Long RELEASE_SUCCESS = 1L;
    //加锁
    public static boolean addLock(Jedis jedis, String lockKey, String userId, int expireTime) {
        //参数解析:
        //1.key 做锁
        //2.value:userId 用用户id 来标识锁是谁的
        //3.nx xx:两种选择:NX:key不存在才set值 XX:key存在时才set值。
        //4.ex px:两种选择:EX:seconds 秒 PX:millSeconds毫秒
        //5.设置过期时间
        String result = jedis.set(lockKey, userId, SET_NOT_EXIST, SET_EXPIRE_TIME, expireTime);
        if (LOCK_SUCCESS.equals(result)) {
            return true;
        }
        return false;
    }
    //解锁
    public static boolean goodByeLock(Jedis jedis, String lockKey, String requestId) {
        //这种写法会出问题
        //String result = jedis.get(lockKey);
        //如果a锁先超时了 这时b获取到了锁,a在解锁时会将b的锁接触
//        if (result.equals(requestId)) {//            jedis.del(lockKey);
//        }
        //这种写法比较正确
        String script = "if redis.call('get', KEYS[1]) == args[1] then return redis.call('del', KEYS[1]) else return 0 end";
        Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));
        if (RELEASE_SUCCESS.equals(result)) {
            return true;
        }
        return false;
    }
}
posted @ 2019-10-15 17:27  皮肤黝黑的小白  阅读(698)  评论(0)    收藏  举报