Redis实现分布式锁

1,实现分布式锁思路

        主要是通过setnx的方法实现分布式锁

2,实现原理

  • 多个jvm同时通过setnx()方法创建相同的一个key,只要谁能够创建成功 谁就能够获取到锁;
  • 如果创建的时候,突然该key已经被其他jvm创建还未过时,则直接等待;
  • 只要能够创建key成功,则开始进入到正常业务逻辑操作,其他没有获取锁进行等待;
  • 正常业务逻辑流程执行完后,通过del删除这个可以来释放锁,从而是其他的请求开始进入到获取锁的资源。
public class RedisLock {

    private static int lockSuccess = 1;

    /**
     * @param lockKey      在Redis中创建的key值
     * @param notLockTimie 尝试获取锁超时时间
     * @return 返回lock成功值
     */
    public String getLock(String lockKey, int notLockTimie, int timeOut) {
        //获取Redis连接
        Jedis jedis = RedisUtil.getJedis();
        // 计算我们尝试获取锁超时时间
        Long endTime = System.currentTimeMillis() + notLockTimie;
        //  当前系统时间小于endTime说明获取锁没有超时 继续循环 否则情况下推出循环
        while (System.currentTimeMillis() < endTime) {
            String lockValue = UUID.randomUUID().toString();
            // 当多个不同的jvm同时创建一个相同的rediskey 只要谁能够创建成功谁就能够获取锁
            if (jedis.setnx(lockKey, lockValue) == lockSuccess) {
                // 加上有效期
                jedis.expire(lockKey, timeOut / 1000);
                return lockValue;
                // 退出循环
            }
            // 否则情况下 继续循环
        }
        try {
            if (jedis != null) {
                jedis.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 释放锁
     *
     * @return
     */
    public boolean unLock(String locKey, String lockValue) {
        //获取Redis连接
        Jedis jedis = RedisUtil.getJedis();
        try {
            // 判断获取锁的时候保证自己删除自己
            if (lockValue.equals(jedis.get(locKey))) {
                return jedis.del(locKey) > 0 ? true : false;
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
        return false;
    }
public class OrderService {
    
    private static final String LOCKKEY = "aaaaa";

    public static void service() {
        // 1.获取锁
        RedisLock redisLock = new RedisLock();
        String lockValue = redisLock.getLock(LOCKKEY, 5000, 5000);
        if (StringUtils.isEmpty(lockValue)) {
            System.out.println(Thread.currentThread().getName() + ",获取锁失败了");
            return;
        }
        // 执行我们的业务逻辑
        System.out.println(Thread.currentThread().getName() + ",获取锁成功:lockValue:" + lockValue);

        // 3.释放锁
        redisLock.unLock(LOCKKEY, lockValue);
    }

    public static void main(String[] args) {
        service();
    }

主要流程就是获取锁,执行业务,释放锁,

这里有几个问题

        1,尝试获取锁为什么次数限制?

                我这里是通过时间来控制他获取锁,因为控制次数有局限性而且不好控制,通过一个范围时间来控制,我这里为5秒,如果不限制他的次数,则他会一直获取,很消耗系统资源。业务逻辑也肯定不是让他一直释放锁 

        2,如果我们业务逻辑5s 内没有执行完毕呢?

                这个其实一开始肯定这个锁的超时时间根据业务场景来预估,其次如果没有执行完则需要延迟一下锁的时间,在提交事务的时候检查锁是否已经超时 如果已经超时则回滚(手动回滚)否则提交。

3,redis与zk实现分布式锁他们之间有什么区别,包括他们的用户场景有哪些

其实个人认为,redis分布式锁比zk分布式锁更灵活,可以更好的通过时间去控制锁的过期时间,而zk它最多就是连接的超时时间来控制锁,就是得业务逻辑什么时候执行完什么时候释放锁,

Redis是采用ap的模式,zk是采用cp的模式,如果为了追求高并发的可以采用redis实现分布式锁,如果是追求数据一致性可以采用zk实分布式锁

       

你可能感兴趣的:(redis,分布式,redis)