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. C#基础篇十小练习

    using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace P03练 ...

  2. 04 - JavaSE之异常处理

    异常的概念(运行期出现的错误) java 异常是 java 提供的用于处理程序中错误的一种机制. 所谓的错误是指在程序运行的过程中发生的一些异常事件.(如:除0溢出,数组下标越界,所要读取的文件不存在 ...

  3. dubbo + zookeeper 简介和部署

    Dubbo简介: Dubbo 是阿里巴巴公司开源(以前不开源)的一个高性能优秀的服务框架, 使得应用可通过高性能的 RPC 实现服务的输入和输出功能, 可以和spring框架无缝集成. 那么这里, 啥 ...

  4. WPF装饰器

    装饰器定义: 装饰器是一种特殊类型的 FrameworkElement,用于向用户提供可视化提示. 对于其他用户,装饰器可用于将功能控点添加到元素中或提供有关控件的状态信息. 装饰器可以在不改变原有的 ...

  5. Jni如何传递并且修改两个基础参数

    最近在开发jni时,需要返回多个参数给java.这个过程中,碰到了一些问题,值得探讨一下.   具体是这样,jni方法jni_do_something作了底层处理后,得出两个int数据,需要将他们的值 ...

  6. 【sh文件权限】无法启动tomcat -bash: ./startup.sh: Permission denied

    今天在Linux上启动Tomcat,结果弹出:-bash: ./startup.sh: Permission denied 的提示. 这是因为用户没有权限,而导致无法执行, 用命令chmod 修改一下 ...

  7. UVa 12657 Boxes in a Line(数组模拟双链表)

    题目链接 /* 问题 将一排盒子经过一系列的操作后,计算并输出奇数位置上的盒子标号之和 解题思路 由于数据范围很大,直接数组模拟会超时,所以采用数组模拟的链表,left[i]和right[i]分别表示 ...

  8. 并发编程之 Exchanger 源码分析

    前言 JUC 包中除了 CountDownLatch, CyclicBarrier, Semaphore, 还有一个重要的工具,只不过相对而言使用的不多,什么呢? Exchange -- 交换器.用于 ...

  9. JSON & Ajax

    Ajax是异步JavaScript和XML是用来在客户端作为一组相互关联的Web开发技术,以创建异步Web应用程序. Ajax模型,Web应用程序可以发送数据和检索数据从一个服务器,而不干扰现有的页面 ...

  10. Thinkphp 图片上传

    案例:广告的增删改查 步骤: 1引用 js 2 填写 input type=" file" 的id 3 填写 url 4后台保存地址 5前台成功后的处理 广告添加页 <div ...