为了防止用户在页面上重复点击或者同时发起多次请求,请求处理需要操作redis缓存,这个时候需要对并发边界进行并发锁控制,实现思路:

由于每个页面发起的请求带的token具备唯一性,可以将token作为锁(key),当前时间作为value进行并发锁控制,分为两个方法:acquireLock和realeaseLock

/**尝试获取锁并设置有效时间*/
53
+ public boolean acquireLock(String lock, long expired){
54
+ boolean isSuccess = false;
55
+ Jedis jedis = jedisPool.getResource();
56
+ long value = System.currentTimeMillis() + expired + 1;
57
+ long acquired = jedis.setnx(lock, String.valueOf(value));
58
+ if (acquired == 1)
59
+ isSuccess = true;
60
+ else {
61
+ long oldValue = Long.valueOf(jedis.get(lock));
62
+ //如果其他资源之前获得锁已经超时
63
+ if (oldValue < System.currentTimeMillis()){
64
+ String getValue = jedis.getSet(lock, String.valueOf(value));
65
+ if (Long.valueOf(getValue) == oldValue)
66
+ isSuccess = true;
67
+ else
68
+ isSuccess = false;
69
+ }
70
+ else isSuccess = false;
71
+ }
72
+ jedisPool.returnResource(jedis);
73
+ return isSuccess;
74
+ }
75
+
76
+ /**释放锁资源*/
77
+ public void releaseLock(String lock){
78
+ Jedis jedis = jedisPool.getResource();
79
+ long currentTime = System.currentTimeMillis();
80
+ if (currentTime < Long.valueOf(jedis.get(lock))){
81
+ jedis.del(lock);
82
+ }
83
+ jedisPool.returnResource(jedis);
84
+ }

经过代码review,对照开源的jedisLock源码,发现以上实现逻辑问题在于,对于jedisPool.getResource如果发生异常,没有对异常进行处理,在外面包装类加上如下处理:

Object runTask(Callback callback) {
Jedis jedis = null;
boolean broken = false;
try {
jedis = jedisPool.getResource();
return callback.onTask(jedis);
} catch (JedisException e) {
broken = handleJedisException(e);
} catch (Exception e) {
log.error("Redis runTask error: ", e);
} finally {
closeResource(jedis, broken);
jedis = null;
}
return null;
}
private boolean handleJedisException(JedisException jedisException) {
if (jedisException instanceof JedisConnectionException) {
log.error("Redis connection lost.", jedisException);
} else if (jedisException instanceof JedisDataException) {
if ((jedisException.getMessage() != null) && (jedisException.getMessage().indexOf("READONLY") != -1)) {
log.error("Redis connection are read-only slave.", jedisException);
} else {
// dataException, isBroken=false
return false;
}
} else {
log.error("Jedis exception happen.", jedisException);
}
return true;
}
private void closeResource(Jedis jedis, boolean conectionBroken) {
try {
if (conectionBroken) {
jedisPool.returnBrokenResource(jedis);
} else {
jedisPool.returnResource(jedis);
}
} catch (Exception e) {
log.error("return back jedis failed, will fore close the jedis.", e);
jedis.close();
}
}

Redis并发锁控制的更多相关文章

  1. 基于redis实现锁控制

    多数据源 数据源1为锁控制,数据源2自定义,可用于存储. 锁:当出现并发的时候为了保证数据的一致性,不会出现并发问题,假设,用户1修改一条信息,用户2也同时修改,会按照顺序覆盖自修改的值,为了避免这种

  2. Redis修改数据多线程并发—Redis并发锁

    本文版权归博客园和作者本人吴双共同所有 .转载爬虫请注明地址,博客园蜗牛 http://www.cnblogs.com/tdws/p/5712835.html 蜗牛Redis系列文章目录http:// ...

  3. Redis学习笔记~Redis并发锁机制

    回到目录 redis客户端驱动有很多,如ServiceStack.Redis,StackExchange.Redis等等,下面我使用ServiceStack.Redis为例,介绍一下在redis驱动中 ...

  4. redis并发锁

    1.应对并发场景 避免操作数据不一致 将对redis加锁 2.考虑到异常状况无法释放锁,导致死锁 将代码块进行try-catch处理 3.考虑try时宕机依然导致死锁 对锁添加时效性,添加过期时间 4 ...

  5. 使用Redis构建全局并发锁

    谈起Redis的用途,小伙伴们都会说使用它作为缓存,目前很多公司都用Redis作为缓存,但是使用Redis仅仅作为缓存未免太大材小用了.深究Redis的原理后你会发现它有很多用途,在很多场景下能够使用 ...

  6. Redis构建全局并发锁

    Redis构建全局并发锁 https://www.cnblogs.com/FG123/p/9990336.html 谈起Redis的用途,小伙伴们都会说使用它作为缓存,目前很多公司都用Redis作为缓 ...

  7. 【redis】基于redis实现分布式并发锁

    基于redis实现分布式并发锁(注解实现) 说明 前提, 应用服务是分布式或多服务, 而这些"多"有共同的"redis"; (2017-12-04) 笑哭, 写 ...

  8. 用压测模拟并发、并发处理(synchronized,redis分布式锁)

    使用工具:Apache an 测压命令: ab -n 100 -c 100 http://www.baidu.com -n代表模拟100个请求,-c代表模拟100个并发,相当于100个人同时访问 ab ...

  9. 使用Redis分布式锁处理并发,解决超卖问题

    一.使用Apache ab模拟并发压测 1.压测工具介绍 $ ab -n 100 -c 100 http://www.baidu.com/ -n表示发出100个请求,-c模拟100个并发,相当是100 ...

随机推荐

  1. MySQL基本数据类型

    MySQL数据类型包括:整型.浮点型.日期类型.字符型,这里用表格的方式详细说明每个数据类型,这些只要记住常用的即可,需要再查阅. 整型 数据类型 存储范围 字节 TINYINT 有符号值:-128 ...

  2. jQuery EasyUI教程之datagrid应用(二)

    上次写到了让数据库数据在网页datagrid显示,我们只是单纯的实现了显示,仔细看的话显示的信息并没有达到我们理想的效果,这里我们丰富一下: 上次显示的结果是这样的 点击查看上篇:jQuery Eas ...

  3. css3 三角形

    https://jsbin.com/gexezo/edit?html,css,output https://jsbin.com/gexezo

  4. 防止SQL注入的方法

    方法1⃣️addslashes(); $username=addslashes($_POST['username']); 方法2⃣️mysql_escape_string(); 方法3⃣️开启魔术引号 ...

  5. VirtualBox虚拟机运行Ubuntu如何不卡

    VirtualBox虚拟机运行Ubuntu如何不卡 转自http://www.xuzefeng.com/post/85.html 上一篇文章<VirtualBox虚拟机安装Ubuntu详细教程& ...

  6. eclipse代码自动补全[转]

    一.每次输入都自动提示 设置Window->preferences->Java->Editor->Content Assist 再右下角Auto activation trig ...

  7. 剔除eclipse的configuration目录[转]

    欢迎和大家交流技术相关问题: 邮箱: jiangxinnju@163.com 博客园地址: http://www.cnblogs.com/jiangxinnju GitHub地址: https://g ...

  8. Vue刨坑

    vue常见问题 1.在自定义组件里,你可以像任何普通元素一样用v-for.eg1: <my-component v-for="item in items"></m ...

  9. 20145218&20145240 《信息安全系统设计基础》实验二 固件设计

    20145218&20145240 <信息安全系统设计基础>实验二 固件设计 实验报告链接:http://www.cnblogs.com/20145240lsj/p/6035512 ...

  10. asp.net Lodop实现批量打印

    1.列表(前台) <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="w_stu ...