基于redis的setnx()、get()、getset()方法 分布式锁

标签: 分布式锁 setnx get getset redis
9人阅读 评论(0) 收藏 举报
分类:

一.redis命令讲解:
setnx()命令:
setnx的含义就是SET if Not Exists,其主要有两个参数 setnx(key, value)。

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

get()命令:
get(key) 获取key的值,如果存在,则返回;如果不存在,则返回nil;
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释放锁;如果大于锁设置的超时时间,则不需要再锁进行处理。

具体代码如下:

实现分布式锁DistributedLockHandler类:

[java] view plain copy
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;  
}  

}

调用Demo类:

[java] view plain copy
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);  
    }  

}  

}

查看评论

分布式锁_Redis_Setnx_getSet

使用Redis-setnx-getset实现分布式锁实现原理: Redis为单进程单线程模式,采用队列模式将并发访问变成串行访问,且多客户端对Redis的连接并不存在竞争关系。redis的SETN...
  • detiantian
  • detiantian
  • 2016年11月27日 14:18
  • 2842

基于redis的setnx()、get()、getset()方法 分布式锁

一.redis命令讲解:  setnx()命令: setnx的含义就是SET if Not Exists,其主要有两个参数 setnx(key, value)。 该方法是原子的,如果key不存在...
  • abbc7758521
  • abbc7758521
  • 2017年09月15日 11:50
  • 1600

Redis实现分布式锁(setnx、getset、incr)以及如何处理超时情况(一)

一、通过setnx实现 1、setnx key value 当且仅当key不存在,将key的值设置为value,并且返回1;若是给定的key已经存在,则setnx不做任何动作,返回0。 pu...
  • weixin_39471249
  • weixin_39471249
  • 2018年01月21日 17:06
  • 587

Java Jedis操作Redis示例(三)——setnx/getset实现分布式锁

转载:http://www.cnblogs.com/0201zcr/p/5942748.html 转载:   http://blog.csdn.net/fengshizty/article/detai...
  • KingCat666
  • KingCat666
  • 2017年09月11日 19:16
  • 979

分布式锁实现方案1、基于Redis的SETNX操作实现的分布式锁

分布式锁实现方案1、基于Redis的SETNX操作实现的分布式锁/** * * 基于Redis的SETNX操作实现的分布式锁 * * @author lzc.java@icloud.com...
  • hl_java
  • hl_java
  • 2017年08月28日 14:36
  • 1395

Redis SETNX命令实现分布式锁

SETNX命令简介命令格式 SETNX key value 将 key 的值设为 value,当且仅当 key 不存在。 若给定的 key 已经存在,则 SETNX 不做任何动作。 SET...
  • shenhaiwen
  • shenhaiwen
  • 2017年04月25日 18:27
  • 2704

redis setnx实现分布式锁

redis在分布式环境下才需要实现锁,一个客户端下不会出现竞争问题 package 使用setnx_getset; import java.io.IOException; import redis....
  • justblues
  • justblues
  • 2017年03月28日 16:14
  • 1024

使用Redis SETNX 命令实现分布式锁

使用Redis的 SETNX 命令可以实现分布式锁,下文介绍其实现方法。SETNX命令命令格式 SETNX key value 将 key 的值设为 value,当且仅当 key 不存在 若给定...
  • lihao21
  • lihao21
  • 2015年10月13日 21:31
  • 58931

Java使用Redis实现分布式锁

思路 主要用的是redis的setnx()函数,利用函数的特性,即成功setnx的话返回1,如果key已经存在,setnx返回0,来判断能否将key插入到redis中。 但是要考虑锁无法正常释放的情...
  • zl18310999566
  • zl18310999566
  • 2017年03月07日 15:33
  • 3463

redis setnx 实现分布式锁和单机锁

对应给定的keys到他们相应的values上。只要有一个key已经存在,MSETNX一个操作都不会执行。由于这种特性,MSETNX可以实现要么所有的操作都成功,要么一个都不执行,这样可以用来设置不同的...
  • pzqingchong
  • pzqingchong
  • 2016年09月12日 20:19
  • 6519
    个人资料
    持之以恒
    等级:
    访问量: 25万+
    积分: 3710
    排名: 1万+
    最新评论