redis 实现分布式锁

1,分布式锁的应用场景之前在zookeeper 的已经说过了,zookpper 的实现方式如下

https://www.cnblogs.com/pickKnow/p/11338579.html

2,基于redis 实现分布式锁

    了解set 和 setnx 命令的不同:

127.0.0.1:6379> set name 'chris'
OK
127.0.0.1:6379> setnx name 'chris'
(integer) 0
127.0.0.1:6379> setnx age 20
(integer) 1
127.0.0.1:6379> set name 'chris'
OK
127.0.0.1:6379> 

    set:往数据库里面插入值,成功,返回ok,key 如果相同,后面的会覆盖前面的

    setnx: 往数据库里面插入值,成功返回1,失败返回0,如果key已经存在,则会插入失败,则会返回0

 

expire key timeout:设置有效时长

name 设置了20秒,过期了key 就不存在了

127.0.0.1:6379> expire name 20
(integer) 1
127.0.0.1:6379> get name
(nil)
127.0.0.1:6379> get age
"20"

del key: 删除key

127.0.0.1:6379> del age

3,基于上面三条命令,可以实现redis分布式锁

    实现思想:在分布式集群环境中,多台JVM 共同去创建key,通过setnx 方式去创建,返回1,代表创建成功,创建成功,则能够获取到锁。

                      给锁设置有效期,根据业务逻辑来设置时长,方式死锁。

                      没有获取到锁的JVM,则一直等待。获取到锁的JVM 实现业务逻辑,逻辑完成,则删除key,将锁释放。

4,实现脚本如下:

private static JedisPool pool = null;
    // 设置最大连接数
    private static int maxTotal =200;
    // 设置最大空闲数
    private static int maxIdle = 8;
    // 设置最大等待时间
    private static long maxWaitMillis = 1000*100;
    // 在borrow一个jedis实例时,是否需要验证,若为true,则所有jedis实例均是可用的
    private static boolean testOnBorrow = true;
    // redis ip
    private static String ip = "192.168.178.110";
    // redis 端口
    private static int port = 6379;
    // redis连接timeout
    private static int timeOut = 6000;
    // redis 上锁的key
    private static String redisLockKey = "redisLockKey";
    // redis 上锁的key 豪秒
    private static long redisLockTimeOut = 6000;

    static {
        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxTotal(maxTotal);
        config.setMaxIdle(maxIdle);
        config.setMaxWaitMillis(maxWaitMillis);
        config.setTestOnBorrow(testOnBorrow);
        pool = new JedisPool(config, ip, port, timeOut);
    }

    @Override
    public boolean lock(String redisLockValue) {
        Jedis resource = null;
        try {
            resource = pool.getResource();
            // 当前时间
            long moment = System.currentTimeMillis();
            // 一把锁的的有效期是 redisLockTimeOut,所以在这个期间内,一直抢key
            // 超过这个时间,说明锁不用抢了,已经过期了,等待下次抢
            while (System.currentTimeMillis() < moment + redisLockTimeOut) {
                Long setnx = resource.setnx(redisLockKey, redisLockValue);
                if (setnx == 1) {
                    // 获取到了锁,给锁加上有效期
                    resource.pexpire(redisLockKey, redisLockTimeOut);
                    return true;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            resource.close();
        }
        return false;
    }

    public void unlock() {
        Jedis resource = null;
        try {
            resource = pool.getResource();
            resource.del(redisLockKey);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            resource.close();
        }
    }

 

posted @ 2019-08-15 14:34  Chris,Cai  阅读(181)  评论(0编辑  收藏  举报