1.原理: 当同一个用户获取锁之后,会让该用户一直持有锁。同样 的用户再次获取,会根据原子性 ,lock返回true。

 /**
* 获取锁(非公平锁), 默认获取超时为2分钟
*/
public boolean lock(){
return lock(GETLOCK_TIMEOUT/);
}
/**
* 获取锁(非公平锁), 获取超时为timeoutSeconds秒
*/
public boolean lock(int timeoutSeconds){
int timeout = timeoutSeconds*;
while (timeout >= ) {
//在同一个JVM内,防止出现以下情况:当已经获取此锁的线程实际业务运行时间超过LOCK_EXPIRE_TIMEOUT时,此锁会再被其它线程获取
if(LOCKED_NAMES.contains(lockname)){
int sleeptime = random.nextInt()+;
try{Thread.sleep(sleeptime);} catch (InterruptedException e) {}
timeout -= sleeptime;
continue;
}
//当分布式程序获取同一个锁时,防止出现以下情况:当已经获取此锁的进程(物理机器)实际业务运行时间超过LOCK_EXPIRE_TIMEOUT时,此锁会再被其它进程(物理机器)获取
String hearbeatFlag = RedisCacheUtil.get(lockname + HEARTBEAT_SUFFIX , String.class );
if(hearbeatFlag!=null){
int sleeptime = random.nextInt()+;
try{Thread.sleep(sleeptime);} catch (InterruptedException e) {}
timeout -= sleeptime;
continue;
} //锁到期时间
long expires = System.currentTimeMillis() + LOCK_EXPIRE_TIMEOUT + ;
boolean ok = setNX(expires);
if (ok) {
//System.out.println(Thread.currentThread().getName()+":获得锁成功,通过setNX");
LOCKED_NAMES.add(lockname);
locked = true;
return locked;
}
//获取当前锁信息
RedisLockValue redisLockValue = get();
if (redisLockValue != null && redisLockValue.getExpireTime() < System.currentTimeMillis()) {
//利用getSet的原子性操作来设置并获取到旧值
RedisLockValue oldRedisLockValue = getSet(expires);
//最先设置的获取锁
if (oldRedisLockValue != null && oldRedisLockValue.getToken().equals(redisLockValue.getToken())) {
//System.out.println(Thread.currentThread().getName()+":获得锁成功,通过getSet");
LOCKED_NAMES.add(lockname);
locked = true;
return locked;
}
}
//防止饥饿线程出现 采用随机休眠时间
int sleeptime = random.nextInt()+;
try{Thread.sleep(sleeptime);} catch (InterruptedException e) {}
timeout -= sleeptime;
} //如果已经超时,但只是因为此时缓存还有值,因为反序列化异常导致GET取不到时,解决死锁问题
try{Thread.sleep();} catch (InterruptedException e) {}
RedisLockValue redisLockValue = get();
if(redisLockValue==null){
//强制删掉即可
LOCKED_NAMES.remove(lockname);
RedisCacheUtil.delete(lockname);
RedisCacheUtil.delete( lockname + HEARTBEAT_SUFFIX );
}
return locked;
}

使用redis 处理高并发场景的更多相关文章

  1. 高并发场景系列(一) 利用redis实现分布式事务锁,解决高并发环境下减库存

    原文:http://blog.csdn.net/heyewu4107/article/details/71009712 高并发场景系列(一) 利用redis实现分布式事务锁,解决高并发环境下减库存 问 ...

  2. 高并发场景之RabbitMQ篇

    上次我们介绍了在单机.集群下高并发场景可以选择的一些方案,传送门:高并发场景之一般解决方案 但是也发现了一些问题,比如集群下使用ConcurrentQueue或加锁都不能解决问题,后来采用Redis队 ...

  3. 高并发场景之RabbitMQ

    高并发场景之RabbitMQ 上次我们介绍了在单机.集群下高并发场景可以选择的一些方案,传送门:高并发场景之一般解决方案 但是也发现了一些问题,比如集群下使用ConcurrentQueue或加锁都不能 ...

  4. Java电商项目,秒杀,抢购等高并发场景的具体场景和一些概念以及处理思路

    这里我借鉴了网上其他大佬的观点: 一:高并发带来的挑战 原因:秒杀抢购会经常会带来每秒几万的高并发场景,为了更快的返回结果给用户. 吞吐量指标QPS(每秒处理请求数),假设一个业务请求响应耗时为100 ...

  5. 关于redis的几件小事(五)redis保证高并发以及高可用

    如果你用redis缓存技术的话,肯定要考虑如何用redis来加多台机器,保证redis是高并发的,还有就是如何让Redis保证自己不是挂掉以后就直接死掉了,redis高可用 redis高并发:主从架构 ...

  6. Redis的高并发、持久化、高可用架构设计

    就是如果你用redis缓存技术的话,肯定要考虑如何用redis来加多台机器,保证redis是高并发的,还有就是如何让Redis保证自己不是挂掉以后就直接死掉了,redis高可用 我这里会选用我之前讲解 ...

  7. MySQL在大数据、高并发场景下的SQL语句优化和"最佳实践"

    本文主要针对中小型应用或网站,重点探讨日常程序开发中SQL语句的优化问题,所谓“大数据”.“高并发”仅针对中小型应用而言,专业的数据库运维大神请无视.以下实践为个人在实际开发工作中,针对相对“大数据” ...

  8. 高并发场景-请求合并(二)揭秘HystrixCollapser-利用Queue和线程池异步实现

    背景 在互联网的高并发场景下,请求会非常多,但是数据库连接池比较少,或者说需要减少CPU压力,减少处理逻辑的,需要把单个查询,用某些手段,改为批量查询多个后返回. 如:支付宝中,查询"个人信 ...

  9. 高并发场景-请求合并(一)SpringCloud中Hystrix请求合并

    背景 在互联网的高并发场景下,请求会非常多,但是数据库连接池比较少,或者说需要减少CPU压力,减少处理逻辑的,需要把单个查询,用某些手段,改为批量查询多个后返回. 如:支付宝中,查询"个人信 ...

随机推荐

  1. FactoryMethod工厂方法模式(创建型模式)

    1.工厂方法模式解决的问题 现在有一个抽象的游戏设施建造系统,负责构建一个现代风格和古典风格的房屋和道路. 前提:抽象变化较慢,实现变化较快(不稳定) 整个抽象的游戏设施建造系统相对变化较慢,本例中只 ...

  2. ASP.NET WebAPI Bearer Authorization

    使用VS2015新建一个WebApi项目. 关键的配置在Startup.Auth.cs里 public partial class Startup { public static OAuthAutho ...

  3. 如何在Notepad++里正确设置java环境(图文环境)

    不多说,直接上干货! 这款软件非常好用!!! Notepad++软件的下载与安装步骤(图文详解) 欢迎大家,加入我的微信公众号:大数据躺过的坑        人工智能躺过的坑       同时,大家可 ...

  4. 《Java多线程编程核心技术》——多线程与同步

    Java多线程 线程可以理解为是在进程中独立运行的子任务. Java多线程 使用方法 Java中实现多线程主要有以下两种方法: 继承Thread,而后实例化该对象调用start()即启动了新线程; 实 ...

  5. Go的方法集

    方法集定义了接口的接受规则. package main import "fmt" type notifier interface { notify() } type user st ...

  6. Web开发者应知的URL编码知识

    原文出处:http://blog.jobbole.com/42246/ 本文首先阐述了人们关于统一资源定位符(URL)编码的普遍的误读,其后通过阐明HTTP场景下的URL encoding 来引出我们 ...

  7. deque双端队列(常用方法总结)

    /*关于C++ STL中deque的学习*/ #include<cstdio> #include<iostream> #include<deque> using n ...

  8. git remote: HTTP Basic: Access denied 错误解决办法

    问题描述: git push 报 HTTP Basic: Access denied 错误 原因:本地git配置的用户名.密码与gitlabs上注册的用户名.密码不一致. 解决方案: 1. 如果账号密 ...

  9. 一个Time TodoList实例了解redux在wepy中的使用

    @subject: wepy-redux-time-todo @author: leinov @date:2018-10-30 @notice: 小程序(wepy)开发群110647537 欢迎加入 ...

  10. MVC使用Flash来显示图片

    Insus.NET实现一些网站模版,如用户能动态变更网站的头,中间或是脚的部位,就是不太确定用户上传的是图片,还是Flash.因此想到一个较好的解决方法,就是使用Flash的组件去显示来源的图片或是. ...