如何利用redis 实现分布式项目枷锁功能

分布式项目,由于用户需要占座需求,防止用户同时进入该链接,导致事务失效,单独使用事务的话,项目在两台服务器上面,导致事务实现不了这种锁,因此添加上了redis单线程锁。

具体实现流程 redis 工具类方法

    // 锁名称
    public static final String LOCK_PREFIX = "redis_lock";
    // 加锁失效时间,毫秒
    public static final int LOCK_EXPIRE = 10000; // ms

/**
     * 最终加强分布式锁
     *
     * @param key
     *            key值
     * @return 是否获取到
     */
    public boolean lock(String key) {
        String lock = LOCK_PREFIX + key;
        // 利用lambda表达式
        return (Boolean) redisTemplate.execute((RedisCallback) connection -> {
            long expireAt = System.currentTimeMillis() + LOCK_EXPIRE + 1;
            log.info("失效的时间是【{}】",String.valueOf(expireAt));
            Boolean acquire = connection.setNX(lock.getBytes(), String.valueOf(expireAt).getBytes());
            
            log.info("查看acquire========"+acquire);
            if (acquire) {
                return true;
            } else {
                byte[] value = connection.get(lock.getBytes());
                
                log.info("查看value========"+value);
                if (Objects.nonNull(value) && value.length > 0) {
                    long expireTime = Long.parseLong(new String(value));
                    log.info("查看expireTime========"+expireTime);
                    // 如果锁已经过期
                    if (expireTime < System.currentTimeMillis()) {
                        log.info("如果锁已经过期,重新加锁");
                        // 重新加锁,防止死锁
                        byte[] oldValue = connection.getSet(lock.getBytes(),
                                String.valueOf(System.currentTimeMillis() + LOCK_EXPIRE + 1).getBytes());
                        log.info("查看oldValue========"+oldValue);
                        
                        
                        Boolean  newLoing= Long.parseLong(new String(oldValue)) < System.currentTimeMillis();
                        log.info("查看Long.parseLong========"+newLoing);
                        return newLoing;
                    }
                }
            }
            return false;
        });
    }
    /**
     * 删除锁
     *
     * @param key
     */
    public void deleteLock(String key) {
        redisTemplate.delete(key);
    }
    

 

调用工具方法

@Override
    public Boolean testRedis(String code) {
        System.out.println("测试分布式锁的应用说明============查看锁状态"+redisManager.exists("redis_lockbbbbbbbbbb"));
        Boolean flag=true;
        System.out.println("测试分布式锁的应用说明============查看continue之后是否执行此日志");
        try {
            while (true) {
                if(redisManager.lock("bbbbbbbbbb")) {
                    Thread.sleep(5000);
                    code.substring(0, 2);
                    System.out.println("测试分布式锁的应用说明=============这是被锁住的进程"+code);
                    System.out.println("测试分布式锁的应用说明=============查看是否进行下面逻辑"+code);
                    redisManager.deleteLock("redis_lockbbbbbbbbbb");
                    return true;
                }else {
                    Thread.sleep(1000);
                    System.out.println("测试分布式锁的应用说明=============这是等待进行释放锁");
                    continue;
                }
            }
        } catch (Exception e) {
            System.out.println("测试分布式锁的应用说明=============抛出异常后发音日志");
            e.printStackTrace();
            
        }
        System.out.println("测试分布式锁的应用说明=============跳出循环后执行这个方法这是直接返回数据");
        return false;
    
    }
这是整个过程的使用,具体实现逻辑:

当用户进入的时候,根据规则生成redis 的key ,同时添加过时时间,如果两个人同时进入,那么第一次进入的人的redis是开锁状态,第二个人进入的时候是闭锁状态, 因此第一个人会在serviceimpl中执行 Thread.sleep(5000);方法,相当于具体的逻辑,当逻辑执行完之后,将锁释放掉,第二个用户会一直走下面的循环,直到锁开了之后才会进入具体的逻辑,

工具类中的逻辑  针对上锁时间而言,并不是在超时之后就将redis 清空,工具的逻辑为当超过过期时间之后,会再次给redis的key加锁,这样第二个请求就会进入,当然这样的问题就是当第一个没有执行完没有自动释放锁的时候,锁自动又加上了, 第二个请求会直接进入,因此枷锁的时间需要想好,尽量在一个请求可以执行完的情况下的时间的几倍。当然所有的逻辑中的要加上try catch 如果逻辑出错,需要在catch中将锁解开。大致就是这个意思!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章