• redis实现分布式锁


    清理邮件的时候发现之前看的一篇关于redis分布式锁实现的文章有人回复- -当时随意扫了眼文章,为了防止发生死锁,思路是使用setnx设置value为本地时间,然后获取锁失败时读取value进行时间比对。。然后我回复了下。。多台应用服务器存在时间不同步的问题。。

    其实使用setnx时设置下redis过期时间简单方便,只是通常在应用程序内通过sdk做这项操作时由于赋值+设置过期不在同一原子性操作中。。所以很多人觉得不可行了。。那就直接使用lua脚本呗,简单方便,原子性操作,性能也OK。

    加锁:aquire_lock_with_timeout.lua

    if redis.call("exists",KEYS[1]) == 0 then
        local lockSrc = redis.call("setex",KEYS[1],unpack(ARGV))
        if lockSrc then
            return "1"
        end
            return "0"
    end
    return "-1"

    释放锁:release_lock.lua

    if redis.call("get",KEYS[1]) == ARGV[1] then
        local lockRelease = redis.call("del",KEYS[1])
            if lockRelease then
                return "1"
            end
                return "0"
    end
    return "-1"

    java为例,加载两个lua脚本,然后简单加锁,释放锁

      @Bean
        @Qualifier("lockScript")
        public RedisScript<Integer> acquireLockWithTimeout() {
            DefaultRedisScript redisScript = new DefaultRedisScript();
            redisScript.setLocation(new ClassPathResource("redis/acquire_lock_with_timeout.lua"));
            redisScript.setResultType(Integer.class);
            return redisScript;
        }
    
    
        @Bean
        @Qualifier("unLockScript")
        public RedisScript<Integer> releaseLock() {
            DefaultRedisScript redisScript = new DefaultRedisScript();
            redisScript.setLocation(new ClassPathResource("redis/release_lock.lua"));
            redisScript.setResultType(Integer.class);
            return redisScript;
        }
        private Integer acquireTimeout;//资源占有锁的时间 秒s
        private Integer acquireInterval;//尝试获取锁的时限 ms
        private Integer lockTime;//尝试获取锁的时间间隔 ms
        
        @Autowired
        private RedisTemplate redisTemplate;
        @Autowired
        @Qualifier("lockScript")
        private RedisScript<Integer> acquireLockWithTimeout;
        @Autowired
        @Qualifier("unLockScript")
        private RedisScript<Integer> releaseLock;
    
         
        public String tryLock(String lockKey) {
            String lockValue = UUID.randomUUID().toString();
            Long endTime = System.currentTimeMillis() + acquireTimeout;
            while (System.currentTimeMillis() < endTime) {
                Integer lockResult = (Integer) redisTemplate.execute(acquireLockWithTimeout, Collections.singletonList(lockKey), lockTime, lockValue);
                if (lockResult.equals(1)) {
                    return lockValue;
                } else {
                    try {
                        Thread.sleep(acquireInterval);
                    } catch (InterruptedException ex) {
                        continue;
                    }
                }
            }
            return "";
        }
     
        public boolean releaseLock(String lockKey, String lockValue) {
            Integer releaseResult = (Integer) redisTemplate.execute(releaseLock, Collections.singletonList(lockKey), lockValue);
            if (releaseResult.equals(1)) {
                return true;
            }
            return false;
        }

    当然java也有更复杂更丰富的组件 redisson

  • 相关阅读:
    层次遍历二叉树时的一个技巧
    合并两个有序链表
    关于指针的引用和“||”运算符的一些心得
    UE4中显示AI Debug信息
    EQS 自定义Context 如何用Testing Pawn 进行测试?
    4.16中Montage的一些变化
    Move Controller UE4键位
    EQS
    获取文件完整路径快捷方法
    同步引擎版本号的简易方法
  • 原文地址:https://www.cnblogs.com/ylsforever/p/8462716.html
Copyright © 2020-2023  润新知