1、在分布式系统中,我们使用锁机制只能保证同一个JVM中一次只有一个线程访问,但是在分布式的系统中锁就不起作用了,这时候就要用到分布式锁(有多种,这里指 redis)

2、在 redis当中可以使用命令 setnx(key, value)来实现分布式锁

  setnx:当key不存在的时候设置成功,返回1,若存在的话返回0表示失败。使用这个命令的话要搭配 expire(key, time)来设置过期时间,但是这种组合存在问题,如下:

   try {
if (redisclient. setnx(key 1) == 1) { //
redisClient.expire(key, 1000);//
}
} finally {
redisClient.del(key);
}

  如上代码,看上去没什么问题,但是极端情况下如果在1处执行完毕2处还没执行这时候这台机器宕机了,那么这个锁将是无期限的,且不会被删除,也就是说设置setnx和expire是两个命令,不具备原子性。 针对这个问题,可以使用 redis2.6版本之后的命令set(key, value, expirefime,NX)来解决,这个命令跟 setnx一样,但是多了过期时间,可以很好的解决这个问题。

3、解决这个问题之后,还存在着一个问题:如果在过期时间内程序代码没执行完,那么其他其他机器线程获得这个锁,这样会造成同时有两个线程执行一段代码,并且A机器(过期还没执行完)中finally会删除key,导致误删到B机器锁(当前获得锁的机器)的情况

  1、此时我们可以在相同的机器上开一个守护线程(如上面例子就在A机器再开一个守护线程),这个线程主要作用是在key快过期的时候进行续命操作,保证代码执行完毕。 2、关于误删,我们可以把value设成线程id,删除前判断一下是否是自己的线程ID,是的话再执行删除,如下面代码

     try {
....
} finally {
if (threadId equals(redisclient get(key)) {//
redisclient.del(key);//
}
}

  这时一般情况都没问题,但是这里的1和2又跟前面的问题类似---不具备原子性,所以还是有出错的可能,但是 redis中没有支持获取删除的原子性命令,该怎么解决呢? 我们可以通过工Lua脚本来解决,例如本例中可以像下面这么写

   String luascript = "if redis call('get', KEYS[1])==ARGV[l] then return redis.call('del', KEYS[1]) else return 0 end";
redisClient.eval(luaScript, Collections.singletonList(key), Collections.singletonList(threadId));

4、到这里,基本就没什么问题了,最终的代码如下

  try {
String luascript = "if redis call('get, KeY[1])==ARGV[l] then return redis.call('del', KEY[1]) else return 0 end";
string threadId = Thread.currentThread() getId();
while (redisclient set(key, threadId, 1000, NX) == 1) {
// dosomething()
}
} finally {
redisClient.eval(luaScript, Collections.singletonList(key), Collections.singletonList(threadId));
}

Redis分布式锁的一点小理解的更多相关文章

  1. 手撕redis分布式锁,隔壁张小帅都看懂了!

    前言 上一篇老猫和小伙伴们分享了为什么要使用分布式锁以及分布式锁的实现思路原理,目前我们主要采用第三方的组件作为分布式锁的工具.上一篇运用了Mysql中的select ...for update实现了 ...

  2. 关于分布式锁原理的一些学习与思考-redis分布式锁,zookeeper分布式锁

    首先分布式锁和我们平常讲到的锁原理基本一样,目的就是确保,在多个线程并发时,只有一个线程在同一刻操作这个业务或者说方法.变量. 在一个进程中,也就是一个jvm 或者说应用中,我们很容易去处理控制,在j ...

  3. Why failover-based implementations are not enough Redis分布式锁实现 SET resource_name my_random_value NX PX 30000

    核心 SET resource_name my_random_value NX PX 30000 Distributed locks with Redis – Redis https://redis. ...

  4. Redis分布式锁 (图解-秒懂-史上最全)

    文章很长,而且持续更新,建议收藏起来,慢慢读! 高并发 发烧友社群:疯狂创客圈(总入口) 奉上以下珍贵的学习资源: 疯狂创客圈 经典图书 : 极致经典 + 社群大片好评 < Java 高并发 三 ...

  5. Redis分布式锁

    Redis分布式锁 分布式锁是许多环境中非常有用的原语,其中不同的进程必须以相互排斥的方式与共享资源一起运行. 有许多图书馆和博客文章描述了如何使用Redis实现DLM(分布式锁管理器),但是每个库都 ...

  6. Redlock(redis分布式锁)原理分析

    Redlock:全名叫做 Redis Distributed Lock;即使用redis实现的分布式锁: 使用场景:多个服务间保证同一时刻同一时间段内同一用户只能有一个请求(防止关键业务出现并发攻击) ...

  7. SpringBoot集成Redis分布式锁以及Redis缓存

    https://blog.csdn.net/qq_26525215/article/details/79182687 集成Redis 首先在pom.xml中加入需要的redis依赖和缓存依赖 < ...

  8. Redis专题(3):锁的基本概念到Redis分布式锁实现

    拓展阅读:Redis闲谈(1):构建知识图谱 Redis专题(2):Redis数据结构底层探秘 近来,分布式的问题被广泛提及,比如分布式事务.分布式框架.ZooKeeper.SpringCloud等等 ...

  9. 死磕 java同步系列之redis分布式锁进化史

    问题 (1)redis如何实现分布式锁? (2)redis分布式锁有哪些优点? (3)redis分布式锁有哪些缺点? (4)redis实现分布式锁有没有现成的轮子可以使用? 简介 Redis(全称:R ...

随机推荐

  1. 【Edu 67】 补题记录

    CF1187D. Subarray Sorting 想要把一个数x换到前面,x一定是小一点的值.由于B串是固定的,A串可调整,我们可以遍历B数组,对于B[i],找到对于在A数组的位子pos,判断1-p ...

  2. hdu 5887 Herbs Gathering (dfs+剪枝 or 超大01背包)

    题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=5887 题解:这题一看像是背包但是显然背包容量太大了所以可以考虑用dfs+剪枝,贪心得到的不 ...

  3. JOBDU 1193 矩阵转置

    啊!!!这道题目今天竟然写错了!!!这道题目巨坑,说不能用数组,结果竟然是用数组做的,吐血!!! 看的所有有关博文,都是用数组做的,晕倒!真的出题人有毛病,出这种题,又不限制运行!!! 以后再遇到这种 ...

  4. 自定义Hive UDAF 实现相邻去重

    内置的两个聚合函数(UDAF) collect_list():多行字符串拼接为一行collect_set():多行字符串拼接为一行并去重多行字符串拼接为一行并相邻去重UDAF:Concat() con ...

  5. 【Offer】[57-1] 【和为S的两个数字】

    题目描述 思路分析 测试用例 Java代码 代码链接 题目描述 输入一个递增排序的数组和一个数字s,在数组中查找两个数,使得它们的和正好是s.如果有多对数字的和等于s,则输出任意一对即可. 牛客网刷题 ...

  6. Go语言标准库之context

    在 Go http包的Server中,每一个请求在都有一个对应的 goroutine 去处理.请求处理函数通常会启动额外的 goroutine 用来访问后端服务,比如数据库和RPC服务.用来处理一个请 ...

  7. GC垃圾收集算法

    JVM中的垃圾收集算法实现涉及大量的程序细节,而且各个平台的虚拟机操作内存的方法又各不相同,这里介绍几种垃圾收集算法的思想. 1.标记-清除算法 这是最基础的垃圾收集算法,分为“标记”和“清除”两个阶 ...

  8. 巨杉Tech | Hbase迁移至SequoiaDB 实战

    背景 在传统银行 IT 架构中,联机交易与统计分析系统往往采用不同的技术与物理设备,通过定期执行的 ETL 将联机交易数据向分析系统中迁移.而作为数据服务资源池,同一份数据可能被不同类型的微服务共享访 ...

  9. 使用opencv训练分类器时,traincascade训练报错:Train dataset for temp stage can not be filled.解决方法

    opencv分类器训练中,出错一般都是路径出错,例如, 1.opencv_traincascade.exe路径 2.负样本路径文件,neg.dat中的样本前路径是否正确 3.移植到别的电脑并修改完路径 ...

  10. 新建Servlet工程——IDEA

    Servlet是sun公司提供的一套接口规范,是运行在服务端的java程序.实现了Servlet的类能够被服务器识别,而普通的java类不能被识别. 1.新建工程 2. 3.工程名字“: 4.在WEB ...