redis实现分布式锁工具类 灰常好用
public interface RedisDistributionLock {
/**
* 加锁成功,返回加锁时间
* @param lockKey
* @param threadName
* @return
*/
public long lock(String lockKey, String threadName); /**
* 解锁, 需要更新加锁时间,判断是否有权限
* @param lockKey
* @param lockValue
* @param threadName
*/
public void unlock(String lockKey, long lockValue, String threadName); /**
* 多服务器集群,使用下面的方法,代替System.currentTimeMillis(),获取redis时间,避免多服务的时间不一致问题!!!
* @return
*/
public long currtTimeForRedis();
}
import java.util.concurrent.TimeUnit; import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer; public class RedisLockImpl implements RedisDistributionLock{
//加锁超时时间,单位毫秒, 即:加锁时间内执行完操作,如果未完成会有并发现象
private static final long LOCK_TIMEOUT = 5*1000; private static final Logger LOG = LoggerFactory.getLogger(RedisLockImpl.class); private StringRedisTemplate redisTemplate; public RedisLockImpl(StringRedisTemplate redisTemplate) {
this.redisTemplate = redisTemplate;
} /**
* 加锁
* 取到锁加锁,取不到锁一直等待知道获得锁
* @param lockKey
* @param threadName
* @return
*/
@Override
public synchronized long lock(String lockKey, String threadName) {
// LOG.info(threadName+"开始执行加锁");
while (true){ //循环获取锁
//锁时间
Long lock_timeout = currtTimeForRedis()+ LOCK_TIMEOUT +1;
if (redisTemplate.execute(new RedisCallback<Boolean>() {
@Override
public Boolean doInRedis(RedisConnection redisConnection) throws DataAccessException {
//定义序列化方式
RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
byte[] value = serializer.serialize(lock_timeout.toString());
boolean flag = redisConnection.setNX(lockKey.getBytes(), value);
return flag;
}
})){
//如果加锁成功
// LOG.info(threadName +"加锁成功 ++++ 111111");
//设置超时时间,释放内存
redisTemplate.expire(lockKey, LOCK_TIMEOUT, TimeUnit.MILLISECONDS);
return lock_timeout;
}else {
//获取redis里面的时间
String result = redisTemplate.opsForValue().get(lockKey);
Long currt_lock_timeout_str = result==null?null:Long.parseLong(result);
//锁已经失效
if (currt_lock_timeout_str != null && currt_lock_timeout_str < System.currentTimeMillis()){
//判断是否为空,不为空时,说明已经失效,如果被其他线程设置了值,则第二个条件判断无法执行
//获取上一个锁到期时间,并设置现在的锁到期时间
Long old_lock_timeout_Str = Long.valueOf(redisTemplate.opsForValue().getAndSet(lockKey, lock_timeout.toString()));
if (old_lock_timeout_Str != null && old_lock_timeout_Str.equals(currt_lock_timeout_str)){
//多线程运行时,多个线程签好都到了这里,但只有一个线程的设置值和当前值相同,它才有权利获取锁
// LOG.info(threadName + "加锁成功 ++++ 22222");
//设置超时间,释放内存
redisTemplate.expire(lockKey, LOCK_TIMEOUT, TimeUnit.MILLISECONDS); //返回加锁时间
return lock_timeout;
}
}
} try {
// LOG.info(threadName +"等待加锁, 睡眠100毫秒");
// TimeUnit.MILLISECONDS.sleep(100);
TimeUnit.MILLISECONDS.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} /**
* 解锁
* @param lockKey
* @param lockValue
* @param threadName
*/
@Override
public synchronized void unlock(String lockKey, long lockValue, String threadName) {
LOG.info(threadName + "执行解锁==========");//正常直接删除 如果异常关闭判断加锁会判断过期时间
//获取redis中设置的时间
String result = redisTemplate.opsForValue().get(lockKey);
Long currt_lock_timeout_str = result ==null?null:Long.valueOf(result); //如果是加锁者,则删除锁, 如果不是,则等待自动过期,重新竞争加锁
if (currt_lock_timeout_str !=null && currt_lock_timeout_str == lockValue){
redisTemplate.delete(lockKey);
LOG.info(threadName + "解锁成功------------------");
}
} /**
* 多服务器集群,使用下面的方法,代替System.currentTimeMillis(),获取redis时间,避免多服务的时间不一致问题!!!
* @return
*/
@Override
public long currtTimeForRedis(){
return redisTemplate.execute(new RedisCallback<Long>() {
@Override
public Long doInRedis(RedisConnection redisConnection) throws DataAccessException {
return redisConnection.time();
}
});
}
}
// 创建一个redis分布式锁
private static final String LOCK_NO = "redis_distribution_lock_no1";
RedisLockImpl redisLock = new RedisLockImpl(stringRedisTemplate);
// 加锁时间
Long lockTime;
String name = "uuid";
if ((lockTime = redisLock.lock((LOCK_NO) + "", name)) != null) {
// 业务逻辑
redisLock.unlock((LOCK_NO) + "", lockTime, name);
}
工具类。
redis实现分布式锁工具类 灰常好用的更多相关文章
- java中redis的分布式锁工具类
使用方式 try { if(PublicLock.getLock(lockKey)){ //这里写代码逻辑,执行完后需要释放锁 PublicLock.freeLock(lockKey); } } ca ...
- redis实现分布式锁--工具类
1.引入依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId> ...
- redis的分布式锁工具LockUtil
/** * 基于redis的分布式锁工具 * * @author yuyufeng * */ public class LockUtil { // 获取redis static JedisPool j ...
- redis分布式锁工具类
目录 (1)需要导入的包 (2)JedisUtil类 (3)jedisPool配置 (4)使用举例 (1)需要导入的包 <dependency> <groupId>redis. ...
- 基于redis的分布式锁实现
1.分布式锁介绍 在计算机系统中,锁作为一种控制并发的机制无处不在. 单机环境下,操作系统能够在进程或线程之间通过本地的锁来控制并发程序的行为.而在如今的大型复杂系统中,通常采用的是分布式架构提供服务 ...
- 用Redis实现分布式锁以及redission使用
原文:https://my.oschina.net/wangnian/blog/668830 前言:分布式环境有很多问题,比如你前一个请求访问的是服务器A,第二个请求访问到了服务器B,就会发生并发重复 ...
- 基于redis的分布式锁的分析与实践
前言:在分布式环境中,我们经常使用锁来进行并发控制,锁可分为乐观锁和悲观锁,基于数据库版本戳的实现是乐观锁,基于redis或zookeeper的实现可认为是悲观锁了.乐观锁和悲观锁最根本的区别在于 ...
- 基于redis的分布式锁二种应用场景
“分布式锁”是用来解决分布式应用中“并发冲突”的一种常用手段,实现方式一般有基于zookeeper及基于redis二种.具体到业务场景中,我们要考虑二种情况: 一.抢不到锁的请求,允许丢弃(即:忽略) ...
- Redis的分布式锁
一.锁的作用 当多线程执行某一业务时(特别是对数据的更新.新增)等操作,可能就会出现多个线程对同一条数据进行修改.其最终的结果一定与你期望的结果“不太一样”,这就与需要一把锁来控制线程排排队了 - j ...
随机推荐
- My latest news(--2016.12.31)
2016.12.31 前一天晚上看 “纪实新闻” ,白天看视频,晚上刷题,看电影<湄公河行动> 2016.12.30 18:36 昨天上午考完了本学期的最后一门课程,下午乒乓+值班,今天 ...
- [洛谷P4609] [FJOI2016]建筑师
洛谷题目链接:[FJOI2016]建筑师 题目描述 小 Z 是一个很有名的建筑师,有一天他接到了一个很奇怪的任务:在数轴上建 \(n\) 个建筑,每个建筑的高度是 \(1\) 到 \(n\) 之间的一 ...
- vue使用jsx/axios拦截器设置
最害怕的就是做过的事情,转几天又忘记了:写过的代码,也模模糊糊不知道哪里去了,所以告诉自己最好把每天遇到的问题记录下来,好,开始. 新公司要搭个vue后台框架,所以用了简简单单的 vue+iview+ ...
- JavaScript 判断手机端访问并跳转 redirect mobile
假如你的手机端网站在 /m 目录下 (function(a,b){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer| ...
- OSCP考试回顾
技术背景 从2011年开始接触学习渗透测试,全职做过的职位有渗透测试,Python后端研发,DevOps,甲方安全打杂. 学习过程 首先考试报名,交钱.买了价值800美元的一个月lab,包含Pente ...
- bootstrap通过ajax请求JSON数据后填充到模态框
1. JSP页面中准备模态框 <!-- 详细信息模态框(Modal) --> <div> <div class="modal fade" id=& ...
- MYSQL的隐式类型转换
官方文档中是这么说的 当操作者使用不同类型的操作数,操作数类型兼容的出现使 转换.一些 发生隐式转换.例如,MySQL会自动 将数字转换为字符串的必要,反之亦然. 也可以将数字转换为字符串明确 使用( ...
- 一起来学redis(一)
redis是一个开源的,高性能的,基于键值对的缓存与存储系统通过提供多种键值数据类型来适应不同场景下的缓存与存储需求. 同时redis的诸多高层级功能使其可以胜任消息队列,任务队列等不同的角色. 特性 ...
- python3.6升级及setuptools、pip安装
升级python3.6 1.打开官网www.python.org,找到最新3.6.3版本,复制下载链接 2.创建/app目录,wget下载到该目录下,编译安装 mkdir /app cd /app w ...
- DroidParts 中文系列教程(基于官方教程)
DroidParts中文系列教程(基于官方教程) (一)DroidParts框架概况 2014年4月18日星期五 11:36 他是一个精心构造的安卓框架,包括下面这些基本功能 DI依赖注入,可以注入V ...