Java Develop——基于 Redis 的分布式锁
来源:互联网 发布:压缩软件mac版 编辑:程序博客网 时间:2024/06/08 09:45
转载请注明出处:http://blog.csdn.net/smartbetter/article/details/78715276
分布式锁应用场景都是用在高并发,大流量场景。
1.用Apache ab压测模拟并发
ab 的使用非常简单:
//-n模拟100个请求,-c模拟100个并发ab -n 100 -c 100 http://www.example.com///-t模拟60秒,-c模拟100个并发,它会在连续60秒内不停的发请求ab -t 60 -c 100 http://www.example.com/
例如常见的秒杀系统,秒杀数据放在 MySQL 这类数据库中时,通过 select…for update 手工加锁可以避免超卖现象。但是为了提升查询速度,常将这些数据放在内存、Redis 中,压测后会发现出现了超卖的现象针对这个现象,可以通过 synchronized 关键字加锁处理并发:
/** * 秒杀的方法 */public synchronized void orderProductMockDiffUser(String productId) {}
这样处理后,再次压测,会发现时间变成了,这是因为加锁处理后,每次访问方法的线程只会有一个线程。这种方法是一种解决方法,但是无法做到细粒度的控制。上面是秒杀的同一个商品的场景,假如说现在有很多商品,每个商品 id 不一样,但是它们都会访问同一个秒杀方法,这会造成一个现象,假如秒杀商品 A 的人非常多,秒杀商品 B 的人非常少,但是两个都会非常慢,因为它们每次访问方法的线程只会有一个线程,无法做到细粒度的控制。还有重要的一点是,这种方法只适合单点的情况,如果水平扩展后 (集群),不同的用户看到的是五花八门的。基于这个问题,就引出了基于 Redis 的分布式锁。
2.基于 Redis 的分布式锁
首先看两个 Redis 的命令:
SETNX key value将key设置值为value,如果key不存在,这种情况下等同SET命令。 当key存在时,什么也不做。SETNX是”SET if Not eXists”的简写。参考: http://www.redis.cn/commands/setnx.htmlGETSET key value自动将key对应到value并且返回原来key对应的value。如果key存在但是对应的value不是字符串,就返回错误。参考: http://www.redis.cn/commands/getset.html
基于 Redis 的分布式锁其实就是在秒杀的方法前后进行加锁、解锁操作:
/** * 秒杀的方法 */public void orderProductMockDiffUser(String productId) { //加锁 //... //解锁}
下面新建一个 Redis 分布式锁的处理,把加锁和解锁写进来:
@Component@Slf4jpublic class RedisLock { private Logger logger = LoggerFactory.getLogger(getClass()); @Autowired private StringRedisTemplate redisTemplate; /** * 加锁 * * @param key * @param value 当前时间+超时时间 * @return */ public boolean lock(String key, String value) { //SETNX命令, 可以设置返回true, 不可以返回false if (redisTemplate.opsForValue().setIfAbsent(key, value)) { return true; } String currentValue = redisTemplate.opsForValue().get(key); //如果锁过期 if (StringUtils.isEmpty(currentValue) && (Long.parseLong(currentValue) < System.currentTimeMillis())) { //GETSET命令, 获取上一个锁的时间 String oldValue = redisTemplate.opsForValue().getAndSet(key, value); if (!StringUtils.isEmpty(oldValue) && oldValue.equals(value)) { return true; } } return false; } /** * 解锁 */ public void unLock(String key, String value) { try { String currentValue = redisTemplate.opsForValue().get(key); if (!StringUtils.isEmpty(currentValue) && currentValue.equals(value)) { redisTemplate.opsForValue().getOperations().delete(key); } } catch (Exception e) { logger.error("【redis分布式锁】解锁异常, {}", e); } }}
使用就很简单了:
private static final int TIMEOUT = 10 * 1000; //超时时间10秒@Autowiredprivate RedisLock redisLock;/** * 秒杀的方法 */public void orderProductMockDiffUser(String productId) { //加锁 long time = System.currentTimeMillis() + TIMEOUT; if(!redisLock.lock(productId, String.valueOf(time))) { throw new SellException(101, "人也太多了, 换个姿势再试试~"); }; //... //解锁 redisLock.unLock(productId, String.valueOf(time));}
到此就完成了分布式锁的处理。
阅读全文
2 0
- Java Develop——基于 Redis 的分布式锁
- Java实现基于Redis的分布式锁
- Java实现基于Redis的分布式锁
- Java实现基于Redis的分布式锁
- Java实现基于Redis的分布式锁
- Java实现基于Redis的分布式锁
- Java Develop——基于 okhttp3 的网络框架设计
- 基于Redis的分布式锁
- 基于Redis的分布式锁
- 基于redis的分布式锁
- 基于redis的分布式锁
- 【分布式缓存】——-基于redis分布式缓存的实现
- 【分布式缓存】——-基于redis分布式缓存的实现
- java 基于redis分布式锁--自己弄的版本
- Java 实现基于Redis的分布式可重入锁
- Java 实现基于Redis的分布式可重入锁
- Java 实现基于Redis的分布式可重入锁
- 基于redis的分布式锁的实现
- 动态规划解343. Integer Break
- linux proc_root_init
- Springboot中使用数据库配置Quartz定时任务
- 小程序
- Expert SQL Server In-Memory OLTP, 2nd Edition.pdf 英文原版 免费下载
- Java Develop——基于 Redis 的分布式锁
- 步进电机相关基础知识
- 1071. 小赌怡情(15)
- Learning Groovy.pdf 英文原版 免费下载
- 1071. 小赌怡情(15)
- 梯度下降算法---Gradient Descent
- TensorFlow 从入门到精通(一):安装和使用
- php直接解析json格式
- 1072. 开学寄语(20)