zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    eclipse中设置自动生成的author,date等注释
    【转】科大校长给数学系学弟学妹的忠告&本科数学参考书
    Eclipse的properties文件中文乱码解决方法
    log4j快速入门
    启动tomcat出现Removing obsolete files from server... Could not clean server of obsolete ……错误
    eclipse构建及运行maven web项目
    Eclipse+Maven创建webapp项目
    linux中通过lsof恢复删除的文件,前题是fd被占用。
    IP工具类-自己动手做个ip解析器
    第4章 集合类
  • 原文地址:https://www.cnblogs.com/ylsforever/p/8462716.html
Copyright © 2011-2022 走看看