Redis-SETNX命令简介
命令格式
SETNX key value
将 key 的值设为 value,当且仅当 key 不存在。
若给定的 key 已经存在,则 SETNX 不做任何动作。
SETNX 是SET if Not eXists的简写。
返回值
返回整数,具体为
- 1,当 key 的值被设置
- 0,当 key 的值没被设置
例子
redis> SETNX mykey “hello”
(integer) 1
redis> SETNX mykey “hello”
(integer) 0
redis> GET mykey
“hello”
redis>
使用SETNX实现分布式锁
多个进程执行以下Redis命令:
SETNX lock.foo <current Unix time + lock timeout + 1>
如果 SETNX 返回1,说明该进程获得锁,SETNX将键 lock.foo 的值设置为锁的超时时间(当前时间 + 锁的有效时间)。
如果 SETNX 返回0,说明其他进程已经获得了锁,进程不能进入临界区。进程可以在一个循环中不断地尝试 SETNX 操作,以获得锁。
解决死锁
考虑一种情况,如果进程获得锁后,断开了与 Redis 的连接(可能是进程挂掉,或者网络中断),如果没有有效的释放锁的机制,那么其他进程都会处于一直等待的状态,即出现“死锁”。
上面在使用 SETNX 获得锁时,我们将键 lock.foo 的值设置为锁的有效时间,进程获得锁后,其他进程还会不断的检测锁是否已超时,如果超时,那么等待的进程也将有机会获得锁。
然而,锁超时时,我们不能简单地使用 DEL 命令删除键 lock.foo 以释放锁。考虑以下情况,进程P1已经首先获得了锁 lock.foo,然后进程P1挂掉了。进程P2,P3正在不断地检测锁是否已释放或者已超时,执行流程如下:
- P2和P3进程读取键 lock.foo 的值,检测锁是否已超时(通过比较当前时间和键 lock.foo 的值来判断是否超时)
- P2和P3进程发现锁 lock.foo 已超时
- P2执行 DEL lock.foo命令
- P2执行 SETNX lock.foo命令,并返回1,即P2获得锁
- P3执行 DEL lock.foo命令将P2刚刚设置的键 lock.foo 删除(这步是由于P3刚才已检测到锁已超时)
- P3执行 SETNX lock.foo命令,并返回1,即P3获得锁
- P2和P3同时获得了锁
从上面的情况可以得知,在检测到锁超时后,进程不能直接简单地执行 DEL 删除键的操作以获得锁。
为了解决上述算法可能出现的多个进程同时获得锁的问题,我们再来看以下的算法。
我们同样假设进程P1已经首先获得了锁 lock.foo,然后进程P1挂掉了。接下来的情况:
- 进程P4执行 SETNX lock.foo 以尝试获取锁
- 由于进程P1已获得了锁,所以P4执行 SETNX lock.foo 返回0,即获取锁失败
- P4执行 GET lock.foo 来检测锁是否已超时,如果没超时,则等待一段时间,再次检测
- 如果P4检测到锁已超时,即当前的时间大于键 lock.foo 的值,P4会执行以下操作
GETSET lock.foo <current Unix timestamp + lock timeout + 1>
- 由于 GETSET 操作在设置键的值的同时,还会返回键的旧值,通过比较键 lock.foo 的旧值是否小于当前时间,可以判断进程是否已获得锁
- 假如另一个进程P5也检测到锁已超时,并在P4之前执行了 GETSET 操作,那么P4的 GETSET 操作返回的是一个大于当前时间的时间戳,这样P4就不会获得锁而继续等待。注意到,即使P4接下来将键 lock.foo 的值设置了比P5设置的更大的值也没影响。
另外,值得注意的是,在进程释放锁,即执行 DEL lock.foo 操作前,需要先判断锁是否已超时。如果锁已超时,那么锁可能已由其他进程获得,这时直接执行 DEL lock.foo 操作会导致把其他进程已获得的锁释放掉。
程序代码
public static boolean acquireLock(String lock) {// 1. 通过SETNX试图获取一个lockboolean success = false;Jedis jedis = pool.getResource(); long value = System.currentTimeMillis() + expired + 1; System.out.println(value); long acquired = jedis.setnx(lock, String.valueOf(value));//SETNX成功,则成功获取一个锁if (acquired == 1) success = true;//SETNX失败,说明锁仍然被其他对象保持,检查其是否已经超时else {long oldValue = Long.valueOf(jedis.get(lock));//超时if (oldValue < System.currentTimeMillis()) {String getValue = jedis.getSet(lock, String.valueOf(value)); // 获取锁成功if (Long.valueOf(getValue) == oldValue) success = true;// 已被其他进程捷足先登了else success = false;}//未超时,则直接返回失败else success = false;} pool.returnResource(jedis);return success;
}
Redis-SETNX命令简介相关推荐
- NoSQL数据库Redis使用命令简介
NoSQL 数据库Redis使用命令简介 NOSQL数据库可以按照它们的数据模型分成4类: 1.键-值对存储库(Key-Value) redis-- 2.BigTable实现(BigTable-imp ...
- Redis Setnx 命令(转)
转自:Redis Setnx 命令 Redis Setnx 命令 Redis 字符串(string) Redis Setnx(SET if Not eXists) 命令在指定的 key 不存在时,为 ...
- 使用 Redis的SETNX命令实现分布式锁
SETNX命令简介 SETNX key value 将key的值设为value,并且仅当key不存在. 若给定的key已经存在,则SETNX不做任何操作. SETNX 是SET if Not eXis ...
- php redis list llen,redis llen list 命令简介
一.命令简介 llen list命令在redis中的主要功能是: 返回一个list(列表)中的元素个数. 二.命令使用说明 命令语法如下: redis 192.168.8.123>llen li ...
- Redis分布式锁/Redis的setnx命令如何设置key的失效时间(同时操作setnx和expire)
Redis的setnx命令是当key不存在时设置key,但setnx不能同时完成expire设置失效时长,不能保证setnx和expire的原子性.我们可以使用set命令完成setnx和expire的 ...
- 场景应用:Redis使用setnx命令实现分布式锁
文章目录 何时需要分布式锁? 如何实现分布式锁? 探究单节点锁:setnx命令 1. 加锁: 2. 解锁: 带来的问题 探究分布式锁:RedLock算法 补充:setnx命令学习 何时需要分布式锁? ...
- redis的lrange_redis lrange list命令简介
一.命令简介 lrange list命令在redis中主要功能是: 根据指定的索引(从开始和结束位置)范围 ,返回索引范围内的元素列表 二.命令使用说明 命令语法如下: redis 192.168.8 ...
- redis setnx 原子性_Redis从入门到深入-分布式锁(26)
1. 分布式锁 1.1 简介 锁 是一种用来解决多个执行线程 访问共享资源 错误或数据不一致问题的工具 如果 把一台服务器比作一个房子,那么 线程就好比里面的住户,当他们想要共同访问一个共享资源,例如 ...
- mset redis_redis mset string 命令简介
一.命令简介 mset string命令在redis中主要功能是: 可以通过一条命令对多个键进行赋值操作, 类似与一次执行多条set命令 二.命令使用说明 命令语法如下: redis 192.168. ...
- Redis学习 - NoSQL简介、redis安装、redis基础知识、数据类型、持久化、订阅发布、主从复制、哨兵模式、缓存击穿和雪崩
学习视频地址:https://www.bilibili.com/video/BV1S54y1R7SB 完结撒花,感谢狂神 文章目录 1. NoSQL 1.1 单机Mysql的演进 1.2 当今企业架构 ...
最新文章
- 菜鸟教程:SQL 通用数据类型
- oracle 输出 三角形,10. 三角形(示例代码)
- 理解Mysql prepare预处理语句:mysql_stmt_init(MYSQL *mysql);
- Java Recruitment(1)
- CentOS配置主机名和主机映射
- 也谈创业企业CEO该拿多少工资
- ue4渲染速度太慢_技术汇丨如何在UE4中实现最佳性能和高质量视觉效果
- neatupload上传文件配置
- 签到系统、评价系统、后台审核系统前后端接口实现总结
- 【预测模型】基于蝙蝠算法改进SVM实现预测matlab源码
- 一篇文章带你了解国企程序员(超详细)
- 光纤是计算机网络介质之一,计算机网络技术传输介质--光纤.pptx
- QPSK数字调制系统在AWGN信道下的BER仿真
- 大一新生必看,自学必看,里昂详解数据结构之堆栈
- Intel Realsense D455 D435i D415 T265 3D实感硬件对比
- 礼盒抖动动画(CocosCreator)
- 在linux系统中 创建用户账户的同时,在Linux系统中大批量建立帐户
- 【R语言】计算信息份额模型 - Computes information share component share weights
- 为什么邮件发的邮箱会进垃圾箱?企业邮箱进垃圾箱有什么处理方法?
- 机器学习——霍夫丁不等式【转】
热门文章
- Autofac的基本使用
- 以匠心正道,以决心致远:毫末智行的自动驾驶之路
- 机器学习 周志华 第一章课后习题
- electron开发问题记录
- 简历之精通 熟练 掌握 熟悉 了解
- linux怎么查看当前系统版本号,Linux下怎么查看当前系统的版本
- DataGrip数据库管理工具安装使用
- 运用java爬虫和python做词云图
- 二维码如何转为链接,看了这篇文章才知道多好用!
- ValueError: greenlet.greenlet size changed, may indicate binary incompatibility. Expected 144 from C