redis缓存工具Jedis进行跨jvm加锁(分布式应用)--不幸暂弃用--能够做第三方锁使用
近期使用redis碰到了多个并发处理同一个缓存的情况。在这样的情况下须要进行加锁机制。
本来想使用java自带的ReadWriteLock进行设置读写锁,这也是上家公司使用的方法。
后来经过商讨,给予排除。原因无他,就是java自带的并不能跨jvm进行加锁,意思就是说Aserver上的write锁无法限制Bserver上的同一个方法,也就是说不适用于分布式部署的环境。
后来经过多方面查看资料。终于决定使用redis自身的方法setnx来进行加锁机制。
网上有非常多关于setnx来进行加锁的方法。只是大部分都会有一个同样的缺陷。就是直接使用setnx加锁、使用del释放锁。这样的情况下呢。假设加锁后发生异常导致没有释放锁,则会成为死锁。
參考:http://blog.csdn.net/java2000_wl/article/details/8740911
再后来有一种新的思路,将setnx和expire结合使用,使得锁有一个有效期,这样当发生异常。有效期一过能够自己主动释放锁。这个算是有一些改进。只是因为setnx和expire是两步操作,不具有原子性。假设setnx操作之后发生异常。还是会造成死锁。
然后就考虑有什么办法能够使得setnx和expire操作同步实现并具有原子性。那么转换一下思路,将setnx的value值设置成当前时间过后的某一刻时间(比方1分钟之后),这个是不是就能够间接取代expire操作了。
是的,这样的方式能够实现。
那么如今就是这样的方式加上del基本能够实现加锁和解锁(而且能够解因异常为释放的锁)。
仅仅只是仍有一些缺陷。由于这样的情况会造成竞争关系,參照:https://github.com/huangz1990/redis/commit/18dbaee4f40f435970a09da427b8f45bd26b4072#diff-b643df753e12d0d07a872f91487c957dR34
依据上面链接给出的解决的方法(即新算法思路)使用有效期来推断之后不是删除key,而是直接给key赋予新值,使用getset,然后推断得到的值和原来的值是否相等。相等即获得锁。最后提供了手动解锁的方法(即删除key就能够)。以下给出代码:
public boolean lock(String key, long timeout) {
boolean lockSuccess = false;
ShardedJedis shardedJedis = pool.getResource();
try{
long start = System.currentTimeMillis();
String lockKey = "lock_"+key;
do{
long result = shardedJedis.setnx(lockKey, String.valueOf(System.currentTimeMillis()+LOCKKEY_EXPIRE_TIME*1000+1));
if(result == 1){
lockSuccess = true;
break;
}else{
String lockTimeStr = shardedJedis.get(lockKey);
if(StringUtils.isNumeric(lockTimeStr)){//假设key存在。锁存在
long lockTime = Long.valueOf(lockTimeStr);
if(lockTime < System.currentTimeMillis()){//锁已过期
String originStr = shardedJedis.getSet(lockKey, String.valueOf(System.currentTimeMillis()+LOCKKEY_EXPIRE_TIME*1000+1));
if(StringUtils.isNoneBlank(originStr)&&originStr.equals(lockTimeStr)){//表明锁由该线程获得
lockSuccess = true;
break;
}
}
}
}
//假设不等待,则直接返回
if(timeout == 0){
break;
}
//等待300ms继续加锁
Thread.sleep(300);
}while((System.currentTimeMillis()-start) < timeout);
}catch(Exception e){
e.printStackTrace();
}finally{
...
}
return lockSuccess;
}
public void unLock(String key) {
ShardedJedis shardedJedis = pool.getResource();
try{
String lockKey = "lock_"+key;
shardedJedis.del(lockKey);
}catch(Exception e){
e.printStackTrace();
}finally{
...
}
}
大概就这些吧~~~
共勉!
------补充:
后来在实际应用其中,用代码測试了一下:使用5000并发线程进行加锁操作,会报非常多的connect timeout异常,因为setnx也是在操作redis和redis进行连接,会占用Jedis连接池中的连接,并且没有获得锁的线程一直在等待。所以我们临时弃用。并且redis是单线程的,读写效率都非常高。除非一些特殊业务须要严格的数据同步,否则redis也不须要加锁。
所以等以后碰到这样的特殊业务再具体学习并慎重使用吧。
特意写出来,防止误导别人~~
-------再补充:
事实上redis本身不须要加锁,须要加锁的是进行redis操作之前的数值计算等,这就须要进行锁控制了。而对于这样的是能够考虑使用redis加锁的。仅仅须要给加锁的redis单独起一个实例就可以,初期这样部署会有资源的浪费。中后期能够这样操作。
redis缓存工具Jedis进行跨jvm加锁(分布式应用)--不幸暂弃用--能够做第三方锁使用的更多相关文章
- Java 使用Redis缓存工具的图文详细方法
开始在 Java 中使用 Redis 前, 我们需要确保已经安装了 redis 服务及 Java redis 驱动,且你的机器上能正常使用 Java. (1)Java的安装配置可以参考我们的 Java ...
- Windows环境下使用Redis缓存工具的图文详细方法
一.简介 redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合)和zset(有序集合). ...
- redis缓存工具类,提供序列化接口
1.序列化工具类 package com.qicheshetuan.backend.util; import java.io.ByteArrayInputStream; import java.io. ...
- redis缓存工具类
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis ...
- springboot集成redis缓存
1.pom.xml增加redis缓存起步依赖(spring-boot-starter-parent包含许多starter版本) <dependency> <groupId>or ...
- RedisPool操作Redis,工具类实例
redis.properties 配置文件内容 redis.pool.maxActive=100redis.pool.maxIdle=20redis.pool.maxWait=3000redis.po ...
- redis缓存介绍以及常见问题浅析
# 没缓存的日子: 对于web来说,是用户量和访问量支持项目技术的更迭和前进.随着服务用户提升.可能会出现一下的一些状况: 页面并发量和访问量并不多,mysql足以支撑自己逻辑业务的发展.那么其实可以 ...
- Java SpringBoot使用Redis缓存和Ehcache
<?xml version="1.0" encoding="UTF-8"?> <ehcache xmlns:xsi="http:// ...
- springboot(七).springboot整合jedis实现redis缓存
我们在使用springboot搭建微服务的时候,在很多时候还是需要redis的高速缓存来缓存一些数据,存储一些高频率访问的数据,如果直接使用redis的话又比较麻烦,在这里,我们使用jedis来实现r ...
随机推荐
- JavaSE复习日记 : 条件判断语句
/* 条件控制语句:if(){}else{} 语法: 第一种结构:有不执行的情况 if(boolean表达式){ //第一位真,就执行里面的语句,为假就不执行 java语句; } 第二种结构: if( ...
- 第一节 生命周期和Zend引擎
一切的开始: SAPI接口 SAPI(Server Application Programming Interface)指的是PHP具体应用的编程接口, 就像PC一样,无论安装哪些操作系统,只要满足了 ...
- windows 下提取目录下所有文件的文件名
tree D:/dir /f >D:/filenames.txt 提取D盘dir目录下所有文件名,写入文件filenames.txt
- 批量删除Kindle library 中的不想要的书籍
这是一个书签形式的脚本 有全选 批量删除什么的 亚马逊本身的删除太麻烦了 网上转的 原帖在这里http://tieba.baidu.com/p/2249582757 改进版本http://t ...
- Nexus 5完全拆解
Nexus 5,由LG制造,配备高通骁龙四核处理器,4.95英寸1080P显示屏,支持4G LTE,运行最新的Android 4.4 KitKat原生操作系统.国外著名拆解网站iFixit第一时间带来 ...
- 浅谈USB设备的VID和PID
根据USB规范的规定,所有的USB设备都有供应商ID(VID)和产品识别码(PID),主机通过不同的VID和PID来区别不同的设备,VID和PID都是两个字节长,其中,供应商ID(VID)由供应商向U ...
- 宣布发布 Windows Azure ExpressRoute,宣告与 Level 3 建立全新的合作伙伴关系并推出关于其他 Azure 服务令人振奋的更新
在我们与世界各地的客户和合作伙伴交谈时,总会听到他们说,希望找到一个提供商帮助他们最大限度地发挥内部部署投资的作用并且能够利用云的灵活性.这是我们构建混合云策略和云操作系统愿景的基本原则.本着我 ...
- android sdk 下载缓慢的问题
原文地址:http://www.oschina.net/question/265039_173445#tags_nav 1.在Android SDK Manager Setting 窗口设置 HTTP ...
- N bulbs(规律)
N bulbs Accepts: 408 Submissions: 1224 Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 655 ...
- Network of Schools(强连通分量+缩点) (问添加几个点最少点是所有点连接+添加最少边使图强连通)
Network of Schools Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 13801 Accepted: 55 ...