zoukankan      html  css  js  c++  java
  • 关于Redis的setnx()、get()、getset()方法以及分布式锁

    一、Redis命令

     1、setnx()命令:

    setnx的含义就是SET if Not Exists,其主要有两个参数 setnx(key, value)。

    该方法是原子的,如果key不存在,则设置当前key成功,返回1;如果当前key已经存在,则设置当前key失败,返回0。

    2、get()命令:

    get(key) 获取key的值,如果存在,则返回;如果不存在,则返回nil;

    3、getset()命令:

    这个命令主要有两个参数 getset(key, newValue)。该方法是原子的,对key设置newValue这个值,并且返回key原来的旧值。

    假设key原来是不存在的,那么多次执行这个命令,会出现下边的效果:

    (1)getset(key, "value1")  返回nil   此时key的值会被设置为value1;

    (2)getset(key, "value2")  返回value1   此时key的值会被设置为value2;

    (3)依次类推!

    二、具体的使用步骤如下:

    1、setnx(lockkey, 当前时间+过期超时时间) ,如果返回1,则获取锁成功;如果返回0则没有获取到锁,转向2。

    2、get(lockkey)获取值oldExpireTime ,并将这个value值与当前的系统时间进行比较,如果小于当前系统时间,则认为这个锁已经超时,可以允许别的请求重新获取,转向3。

    3、计算newExpireTime=当前时间+过期超时时间,然后getset(lockkey, newExpireTime) 会返回当前lockkey的值currentExpireTime。

    4、判断currentExpireTime与oldExpireTime 是否相等,如果相等,说明当前getset设置成功,获取到了锁。如果不相等,说明这个锁又被别的请求获取走了,那么当前请求可以直接返回失败,或者继续重试。

    5、在获取到锁之后,当前线程可以开始自己的业务处理,当处理完毕后,比较自己的处理时间和对于锁设置的超时时间,如果小于锁设置的超时时间,则直接执行delete释放锁;如果大于锁设置的超时时间,则不需要再锁进行处理。

    三、实例代码

    1、实现分布式锁DistributedLockHandler类:

    package tk.mybatis.springboot.distributedLock;
     
    import org.springframework.stereotype.Service;
    import redis.clients.jedis.Jedis;
     
    @Service("distributedLockHandler")
    public class DistributedLockHandler {
     
        private static final Integer Lock_Timeout = 3;
     
        private Jedis jedis;
     
        /**
         * 外部调用加锁的方法
         * @param lockKey 锁的名字
         * @param timeout 超时时间(放置时间长度,如:5L)
         * @return
         */
        public boolean tryLock(String lockKey, Long timeout) {
            try {
                Long currentTime = System.currentTimeMillis();//开始加锁的时间
                boolean result = false;
                
                while (true) {
                    if ((System.currentTimeMillis() - currentTime) / 1000 > timeout) {//当前时间超过了设定的超时时间
                        System.out.println("Execute DistributedLockHandler.tryLock method, Time out.");
                        break;
                    } else {
                        result = innerTryLock(lockKey);
                        if (result) {
                            break;
                        } else {
                            System.out.println("Try to get the Lock,and wait 100 millisecond....");
                            Thread.sleep(100);
                        }
                    }
                }
                return result;
            } catch (Exception e) {
                System.out.println("Failed to run DistributedLockHandler.getLock method."+ e);
                return false;
            }
        }
        
        /**
         * 释放锁
         * @param lockKey 锁的名字
         */
        public void realseLock(String lockKey) {
            if(!checkIfLockTimeout(System.currentTimeMillis(), lockKey)){
                jedis.del(lockKey);
            }
        }
        
        /**
         * 内部获取锁的实现方法
         * @param lockKey 锁的名字
         * @return
         */
        private boolean innerTryLock(String lockKey) {
            
            long currentTime = System.currentTimeMillis();//当前时间
            String lockTimeDuration = String.valueOf(currentTime + Lock_Timeout + 1);//锁的持续时间
            Long result = jedis.setnx(lockKey, lockTimeDuration);
            
            if (result == 1) {
                return true;
            } else {
                if (checkIfLockTimeout(currentTime, lockKey)) {
                    String preLockTimeDuration = jedis.getSet(lockKey, lockTimeDuration);
                    if (currentTime > Long.valueOf(preLockTimeDuration)) {
                        return true;
                    }
                }
                return false;
            }
            
        }
     
        /**
         * 判断加锁是否超时
         * @param currentTime 当前时间
         * @param lockKey 锁的名字
         * @return
         */
        private boolean checkIfLockTimeout(Long currentTime, String lockKey) {
            if (currentTime > Long.valueOf(jedis.get(lockKey))) {//当前时间超过锁的持续时间
                return true;
            } else {
                return false;
            }
        }
     
        public DistributedLockHandler setJedis(Jedis jedis) {
            this.jedis = jedis;
            return this;
        }
     
    }

    2、调用Demo类:

    package tk.mybatis.springboot.distributedLock;
     
    import redis.clients.jedis.Jedis;
     
    /**
     * 基于redis的setnx()、get()、getset()方法 分布式锁
     * @author KF01
     *
     */
    public class Demo {
    private static final String lockKey = "Lock.TecentIm_Interface_Counter"; public static void main(String[] args) { Jedis jedis = new Jedis("127.0.0.1", 6379); DistributedLockHandler distributedLockHandler = new DistributedLockHandler().setJedis(jedis); try{ boolean getLock = distributedLockHandler.tryLock(lockKey, Long.valueOf(5)); if(getLock){ // Do your job System.out.println("Do your job........"); } }catch(Exception e){ System.out.println(e); }finally { distributedLockHandler.realseLock(lockKey); } } }
  • 相关阅读:
    [转] EJB 3和Spring技术体系比较
    JBOSS只能本机localhost和127.0.0.1能访问的解决
    JBOSS EAP 6.0+ Standalone模式安装成Windows服务
    IBM WebSphere MQ 7.5基本用法
    maven学习(上)- 基本入门用法
    mac下环境变量、maven3.1.1 及 jdk1.7.0.45配置
    java:读/写配置文件
    java:使用匿名类直接new接口
    java与c#的反射性能比较
    XmlSpy / XSD 以及 验证
  • 原文地址:https://www.cnblogs.com/ZJOE80/p/14759504.html
Copyright © 2011-2022 走看看