利用redis可以实现分布式锁,demo如下:

 /**
* 保存每个线程独有的token
*/
private static ThreadLocal<String> tokenMap = new ThreadLocal<>(); /**
* redis实现分布式可重入锁,并不保证在过期时间内完成锁定内的任务,需根据业务逻辑合理分配seconds
*
* @param lock
* 锁的名称
* @param seconds
* 锁定时间,单位 秒
* token
* 对于同一个lock,相同的token可以再次获取该锁,不相同的token线程需等待到unlock之后才能获取
* @return
*/
public boolean lock(final String lock,final int seconds) {
// @param token 对于同一个lock,相同的token可以再次获取该锁,不相同的token线程需等待到unlock之后才能获取
String token = tokenMap.get();
if (StringUtil.isBlank(token)) {
token = UUIDGenerator.getUUID();
tokenMap.set(token);
}
boolean flag = false;
Jedis client = null;
try {
client = jedisPool.getResource();
String ret = client.set(lock, token, "NX", "EX", seconds);
if (ret == null) {// 该lock的锁已经存在
// String origToken = client.get(lock);// 即使lock已经过期也可以
31 // if (token.equals(origToken)||origToken==null) {// token相同默认为同一线程,所以token应该尽量长且随机,保证不同线程的该值不相同
32 // ret = client.set(lock, token, "NX", "EX", seconds);//
33 // if ("OK".equalsIgnoreCase(ret))
34 // flag = true;
35 // }
ret=client.cas(lock,origToken,token,seconds);
if("OK".equalsIgnoreCase(ret)){
flag=true;
}
} else if ("OK".equalsIgnoreCase(ret))
flag = true;
} catch (Exception e) {
logger.error(" lock{} 失败");
throw new RedisException(e);
} finally {
if (client != null)
client.close();
}
return flag;
} /**
* redis可以保证lua中的键的原子操作 unlock:lock调用完之后需unlock,否则需等待lock自动过期
*
* @param lock
* token
* 只有线程已经获取了该锁才能释放它(token相同表示已获取)
*/
public void unlock(final String lock) {
Jedis client = null;
final String token = tokenMap.get();
if (StringUtil.isBlank(token))
return;
try {
client = jedisPool.getResource();
final String script = "if redis.call(\"get\",\"" + lock + "\") == \"" + token + "\"then return redis.call(\"del\",\"" + lock + "\") else return 0 end ";
client.eval(script);
} catch (Exception e) {
logger.error(" unlock{} 失败");
throw new RedisException(e);
} finally {
if (client != null)
client.close();
} } public static void main(String[] args) {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
final RedisUtil redis = ctx.getBean(RedisUtil.class);
for (int i = 0; i < 100; i++) {
new Thread(new Runnable() {
String key = "cheng"; @Override
public void run() {
boolean lock = redis.lock(key, 30);
System.out.print(lock + "-"); }
}).start();
;
}
// redis.unlock(key);
// ctx.close();
}

  

运行main方法:

结果:true-false-......false-

redis实现分布式可重入锁的更多相关文章

  1. Springboot基于Redisson实现Redis分布式可重入锁【案例到源码分析】

    一.前言 我们在实现使用Redis实现分布式锁,最开始一般使用SET resource-name anystring NX EX max-lock-time进行加锁,使用Lua脚本保证原子性进行实现释 ...

  2. Golang可重入锁的实现

    Golang可重入锁的实现 项目中遇到了可重入锁的需求和实现,具体记录下. 什么是可重入锁 我们平时说的分布式锁,一般指的是在不同服务器上的多个线程中,只有一个线程能抢到一个锁,从而执行一个任务.而我 ...

  3. Redis分布式锁—Redisson+RLock可重入锁实现篇

    前言 平时的工作中,由于生产环境中的项目是需要部署在多台服务器中的,所以经常会面临解决分布式场景下数据一致性的问题,那么就需要引入分布式锁来解决这一问题. 针对分布式锁的实现,目前比较常用的就如下几种 ...

  4. redis分布式锁-可重入锁

    redis分布式锁-可重入锁 上篇redis实现的分布式锁,有一个问题,它不可重入. 所谓不可重入锁,即若当前线程执行某个方法已经获取了该锁,那么在方法中尝试再次获取锁时,就会获取不到被阻塞. 同一个 ...

  5. redis实现分布式锁需要考虑的因素以及可重入锁实现

    死锁 错误例子 解决方式  防止死锁 通过设置超时时间  不要使用setnx key   expire 20  不能保证原子性 如果setnx程序就挂了 没有执行expire就死锁了  reidis2 ...

  6. 【分布式锁】06-Zookeeper实现分布式锁:可重入锁源码分析

    前言 前面已经讲解了Redis的客户端Redission是怎么实现分布式锁的,大多都深入到源码级别. 在分布式系统中,常见的分布式锁实现方案还有Zookeeper,接下来会深入研究Zookeeper是 ...

  7. Redisson 分布式锁源码 01:可重入锁加锁

    前言 相信小伙伴都是使用分布式服务,那一定绕不开分布式服务中数据并发更新问题! 单系统很容易想到 Java 的各种锁,像 synchronize.ReentrantLock 等等等,那分布式系统如何处 ...

  8. ZooKeeper 分布式锁 Curator 源码 01:可重入锁

    前言 一般工作中常用的分布式锁,就是基于 Redis 和 ZooKeeper,前面已经介绍完了 Redisson 锁相关的源码,下面一起看看基于 ZooKeeper 的锁.也就是 Curator 这个 ...

  9. Redisson分布式锁学习总结:可重入锁 RedissonLock#lock 获取锁源码分析

    原文:Redisson分布式锁学习总结:可重入锁 RedissonLock#lock 获取锁源码分析 一.RedissonLock#lock 源码分析 1.根据锁key计算出 slot,一个slot对 ...

随机推荐

  1. 单词接龙dfs洛谷

    题目传送门:https://www.luogu.org/problem/show?pid=1019#sub 典型的爆搜,每次更新最大龙长度即可 搜索每个字符串编号,与已经连接好的字符串进行比较,以此往 ...

  2. Springboot Mybatis Redis 实现二级缓存

    前言 什么是mybatis二级缓存? 二级缓存是多个sqlsession共享的,其作用域是mapper的同一个namespace. 即,在不同的sqlsession中,相同的namespace下,相同 ...

  3. jQuery noConflict() 方法----与其他javaScript插件冲突时

    1,全名代替----jQuery: $.noConflict(); jQuery(document).ready(function(){ jQuery("button").clic ...

  4. 使用邮件激活授权/ LightningChart license

    在无网络连接的情况下,可以采用邮件的方式激活授权. 先打开License Manager,然后选 Activate/Deactivate via email, 如下图所示: 此邮件将自动发送到 lic ...

  5. Python爬虫(十二)_XPath与lxml类库

    Python学习指南 有同学说,我正则用的不好,处理HTML文档很累,有没有其他的方法? 有!那就是XPath,我们可以用先将HTML文档转换成XML文档,然后用XPath查找HTML节点或元素. 什 ...

  6. Python Django CMDB项目实战之-2创建APP、建模(models.py)、数据库同步、高级URL、前端页面展示数据库中数据

    基于之前的项目代码来编写 Python Django CMDB项目实战之-1如何开启一个Django-并设置base页index页文章页面 现在我们修改一个文章列表是从数据库中获取数据, 下面我们就需 ...

  7. webStorm和Sublime使用列编辑命令

    webStorm可以像Sublime一样使用列编辑,只是区别在于webStorm只可以编辑连续列表. 按住alt键鼠标选择一列,然后输入文字就会编辑多行,这个功能很赞,比较实用(按住ALT键选中之后, ...

  8. 20150605面试汇总--js与java的差别

    javascript与java都是编程语言,不同在于代码格式不同. js基于对象,java是面向对象: java是强变量.编译前必须作出声明.js是弱变量,使用前不需做声明: JavaScript 是 ...

  9. windows 怎样查看port占用情况

    開始--执行--cmd 进入命令提示符 输入netstat -ano 就可以看到全部连接的PID 之后在任务管理器中找到这个PID所相应的程序假设任务管理器中没有PID这一项,能够在任务管理器中选&q ...

  10. 行编辑距离Edit Distance——动态规划

    题目描写叙述: 给定一个源串和目标串.可以对源串进行例如以下操作:  1. 在给定位置上插入一个字符  2. 替换随意字符  3. 删除随意字符 写一个程序.返回最小操作数,使得对源串进行这些操作后等 ...