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对 ...
随机推荐
- React 页面间传值的个人总结
react 组件之间传值的方案有很多,下面是我个人经验的总结 props 来传递值 传值方式: 通过props 获取值 通过props 提供的func去修改值 优点: 不需要任何第三方的组件,纯rea ...
- springboot之Jwt验证
简介 什么是JWT(Json Web Token) jwt是为了在网络应用环境间传递声明而执行的一种基于json的开放标准.该token被设计紧凑且安全的,特别适用于SSO场景. jwt的声明一般被用 ...
- mysql 有哪些索引
Mysql支持哪几种索引 从数据结构角度 1.B+树索引(O(log(n))):关于B+树索引,可以参考 MySQL索引背后的数据结构及算法原理 2.hash索引:a 仅仅能满足"=&quo ...
- 360提供的php防注入代码
<?php //Code By Safe3 function customError($errno, $errstr, $errfile, $errline) { echo "< ...
- 负载均衡之 nginx
什么是负载均衡负载均衡(Load Balance)是分布式系统架构设计中必须考虑的因素之一,它通常是指,将请求/数据[均匀]分摊到多个操作单元上执行,负载均衡的关键在于[均匀].在使用nginx负载均 ...
- svn搭建文档
1.制作本地yum源 a)挂载光盘 [root@localhost ~]# mount /dev/cdrom /mnt b)删除/etc/yum.repos.d目录所有的repo文件 [root@ ...
- 16进制到byte转换
我们经常会看到这样的语法 (byte) 0xAD 0xAD实际是个16进制,转换成二进制为:10101101,转换成10进制是:173,它是个正数 10101101只是int的简写,int由4个byt ...
- Python---初识堡垒机
在学习堡垒机之前,我们需要首先了解下Python的paramiko模块,该模块机遇SSH用于连接远程服务器并执行相关操作. SSHClient 用于连接远程服务器并执行基本命令 基于用户名密码连接: ...
- TP3.2 图片上传及缩略图
基于TP自带的上传文件的类, Think/Upload.class.php 设置表单的enctype属性 下面是上传的具体方法 /** * 图片上传处理 * @param [String] $path ...
- java.lang.RuntimeException: Canvas: trying to use a recycled bitmap android.graphics.Bitmap@412d7230
近期遇到了如标题这种错误,再次记录解决方法.本文參考帖子: http://bbs.csdn.net/topics/390196217 出现此bug的原因是在内存回收上.里面用Bitamp的代码为: t ...