redis实现分布式可重入锁
利用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实现分布式可重入锁的更多相关文章
- Springboot基于Redisson实现Redis分布式可重入锁【案例到源码分析】
一.前言 我们在实现使用Redis实现分布式锁,最开始一般使用SET resource-name anystring NX EX max-lock-time进行加锁,使用Lua脚本保证原子性进行实现释 ...
- Golang可重入锁的实现
Golang可重入锁的实现 项目中遇到了可重入锁的需求和实现,具体记录下. 什么是可重入锁 我们平时说的分布式锁,一般指的是在不同服务器上的多个线程中,只有一个线程能抢到一个锁,从而执行一个任务.而我 ...
- Redis分布式锁—Redisson+RLock可重入锁实现篇
前言 平时的工作中,由于生产环境中的项目是需要部署在多台服务器中的,所以经常会面临解决分布式场景下数据一致性的问题,那么就需要引入分布式锁来解决这一问题. 针对分布式锁的实现,目前比较常用的就如下几种 ...
- redis分布式锁-可重入锁
redis分布式锁-可重入锁 上篇redis实现的分布式锁,有一个问题,它不可重入. 所谓不可重入锁,即若当前线程执行某个方法已经获取了该锁,那么在方法中尝试再次获取锁时,就会获取不到被阻塞. 同一个 ...
- redis实现分布式锁需要考虑的因素以及可重入锁实现
死锁 错误例子 解决方式 防止死锁 通过设置超时时间 不要使用setnx key expire 20 不能保证原子性 如果setnx程序就挂了 没有执行expire就死锁了 reidis2 ...
- 【分布式锁】06-Zookeeper实现分布式锁:可重入锁源码分析
前言 前面已经讲解了Redis的客户端Redission是怎么实现分布式锁的,大多都深入到源码级别. 在分布式系统中,常见的分布式锁实现方案还有Zookeeper,接下来会深入研究Zookeeper是 ...
- Redisson 分布式锁源码 01:可重入锁加锁
前言 相信小伙伴都是使用分布式服务,那一定绕不开分布式服务中数据并发更新问题! 单系统很容易想到 Java 的各种锁,像 synchronize.ReentrantLock 等等等,那分布式系统如何处 ...
- ZooKeeper 分布式锁 Curator 源码 01:可重入锁
前言 一般工作中常用的分布式锁,就是基于 Redis 和 ZooKeeper,前面已经介绍完了 Redisson 锁相关的源码,下面一起看看基于 ZooKeeper 的锁.也就是 Curator 这个 ...
- Redisson分布式锁学习总结:可重入锁 RedissonLock#lock 获取锁源码分析
原文:Redisson分布式锁学习总结:可重入锁 RedissonLock#lock 获取锁源码分析 一.RedissonLock#lock 源码分析 1.根据锁key计算出 slot,一个slot对 ...
随机推荐
- CDH升级
升级主要分为两部分1.CM的升级.2.CDH的升级 CM的升级 两种升级方法 1.使用package 2.使用Tarballs升级方法,参照官方升级指引,Tarball中包含了Cloudera Man ...
- SPOJ SERGRID - Grid BFS
SERGRID - Grid no tags You are on an nxm grid where each square on the grid has a digit on it. From ...
- 深入理解php内核 编写扩展_III- 资源
原文:http://devzone.zend.com/article/1024-Extension-Writing-Part-III-Resources 编写扩展_III- 资源 介绍 资源 初始化资 ...
- 【算法】字典的诞生:有序数组 PK 无序链表
参考资料 <算法(java)> — — Robert Sedgewick, Kevin Wayne <数据结构> ...
- google guava cache缓存基本使用讲解
代码地址:https://github.com/vikde/demo-guava-cache 一.简介 guava cache是google guava中的一个内存缓存模块,用于将数据缓存到JVM内存 ...
- Python2/3中的urllib库
urllib库对照速查表 Python2.X Python3.X urllib urllib.request, urllib.error, urllib.parse urllib2 urllib.re ...
- 运行循环 - RunLoop
1.RunLoop简介 1.1 什么是RunLoop 简单来说就是:运行循环,可以理解成一个死循环,一直在运行. RunLoop实际上就是一个对象,这个对象用来处理程序运行过程中出现的各种事件(触摸. ...
- css中设置div水平居中,margin:0px auto无用的情况
在CSS中加了margin:0px auto;却没有效果,不能实现居中的问题!margin:0px auto;意思就是:上下边界为0.左右依据宽度自适应!就是水平居中的意思.无效的原因是,当你没有设置 ...
- FTP命令具体解释(含操作实例)
以下是微软命令行FTPclient命令大全.假设你想使用"未加工(RAW)"FTP命令而非以下翻译过的请參考:http://www.nsftools.com/tips/RawFTP ...
- Android setContentView方法解析(一)
在Activity的生命周期onCreate中.我们一般都习惯性的调用setContentView(int layoutResID)方法,把布局文件载入到页面上来.以下我们就来通过源代码一步步的分析怎 ...