1.Redis Lock
使用场景
同步锁,让业务方法在锁设定的时间内是同步执行的
redisService.setIfAbsent
redisService.expire
@PostMapping("/update")
public MMHResponse saveOrUpdateMemberBaby(@RequestBody SaveOrUpdateMemberBabyForm form){
GlobalLock globalLock = null;
try {
globalLock = GlobalLockRedisImpl.getInstance(key);
globalLock.lock();
//TODO ...业务方法
return SuccessResponse.newInstance();
} catch (Exception e) {
logger.error("[ebiz-user-service][saveOrUpdateMemberBaby]操作失败,原因{}", StackTraceLogUtil.getStackTraceAsString(e));
return ErrorResponse.newInstance("操作失败");
} finally {
//释放锁
if (globalLock != null) {
globalLock.unlock();
}
}
}
不难看出,redis不参与业务逻辑代码,仅仅作一个定时的开发,保证在某个时间段内 业务代码不受干扰
我们再来看一下lock 方法
GlobalLock
/**
* <pre>
* Example 1: 强制获取锁,会阻塞, 超时失败会抛出异常
* GlobalLock lock = GlobalLockRedisImpl.getInstance("local key name")
* try{
* lock.lock(5);
* doSamething()
* } catch(GDSystemException e) {
* //获取锁异常
* } finally {
* lock.unlock();
* }
*
*
* Example 2: 尝试获取锁, 失败会直接返回false
* GlobalLock lock = ...;
* if (lock.tryLock()) {
* try {
* // manipulate protected state
* } finally {
* lock.unlock();
* }
* } else {
* // perform alternative actions
* }
* </pre>
*/
public interface GlobalLock { /**
* 申请加锁,此操作为阻塞操作,且不响应线程中断
* 超过指定时间会抛出异常,程序需要对异常处理, 最大锁住时间为1分钟
*
* @throws RuntimeException 在指定的时间内获取锁失败
*/
void lock(int timeout) throws RuntimeException; /**
* 申请加锁, 最大时间30秒
*
* @throws RuntimeException
*/
void lock() throws RuntimeException; /**
* Acquires the lock only if it is free at the time of invocation.
* <p>
* <p>Acquires the lock if it is available and returns immediately
* with the value {@code true}.
* If the lock is not available then this method will return
* immediately with the value {@code false}.
* <p>
* <p>A typical usage idiom for this method would be:
* <pre>
* Lock lock = ...;
* if (lock.tryLock()) {
* try {
* // manipulate protected state
* } finally {
* lock.unlock();
* }
* } else {
* // perform alternative actions
* }
* </pre>
* This usage ensures that the lock is unlocked if it was acquired, and
* doesn't try to unlock if the lock was not acquired.
*
* @return {@code true} if the lock was acquired and
* {@code false} otherwise
*/
boolean tryLock(); /**
* 释放锁
*/
void unlock(); }
GlobalLockRedisImpl
/**
* 基于redis实现的全局锁
*/
public class GlobalLockRedisImpl implements GlobalLock { private ILog logger = LogFactory.getLog(GlobalLockRedisImpl.class, LogBusinessModule.TRACE_LOG); private RedisService redisService; // timeout(ms)
private static final int TIME_OUT = 30; // private Jedis jedis;
private String key; // state flag
private volatile boolean locked = false; private static ConcurrentMap<String, GlobalLock> map = Maps.newConcurrentMap(); /**
* 构造函数
*
* @param key
*/
private GlobalLockRedisImpl(String key) {
this.key = "_LOCK_" + key;
this.redisService = (RedisService) MyApplicationContext.getBean("redisService");
} public static GlobalLock getInstance(String key) {
GlobalLock globalLock = map.get(key);
if (globalLock == null) {
map.put(key, new GlobalLockRedisImpl(key));
return map.get(key);
}
return globalLock;
} public boolean tryLock() {
long result = redisService.increment(key);
boolean success = result <= 1;
if (!success) {// 锁已被占用,等待释放
result = redisService.increment(key);
success = result <= 1;
}
if (success) {// 处理锁的自动释放
redisService.set(key, String.valueOf(result), TIME_OUT);
locked = true;
if (logger.isDebugEnabled()) {
logger.debug("尝试获取锁{}成功, 锁将在 {} 秒后释放", key, TIME_OUT);
}
}
return success;
} public void lock(int timeout) throws RuntimeException {
long nanoTime = System.nanoTime();
do {
if (redisService.setIfAbsent(key, key)) {
redisService.expire(key, 1, TimeUnit.MINUTES); //设定锁过期时间为1分钟
locked = true;
if (logger.isDebugEnabled()) {
logger.debug("get key: {} lock success! -- {} 毫秒", key, TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - nanoTime));
}
return;
}
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
} while ((System.nanoTime() - nanoTime) < TimeUnit.SECONDS.toNanos(timeout));
throw new RuntimeException("获取锁超时, 消耗时间: " + TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - nanoTime) + "毫秒");
} public void lock() throws RuntimeException {
lock(TIME_OUT);
} public void unlock() {
if (locked) {
redisService.delete(key);
}
} }
public void lock() throws GDSystemException {
lock(30);
}
public void lock(int timeout) throws GDSystemException {
long nanoTime = System.nanoTime();
while(!redisService.setIfAbsent(this.key, this.key)) {
try {
Thread.sleep(300L);
} catch (InterruptedException var5) {
var5.printStackTrace();
}
if(System.nanoTime() - nanoTime >= TimeUnit.SECONDS.toNanos((long)timeout)) {
throw new GDSystemException("获取锁超时, 消耗时间: " + TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - nanoTime) + "毫秒");
}
}
this.redisService.expire(this.key,60, TimeUnit.SECONDS);
this.locked = true;
if(logger.isDebugEnabled()) {
logger.debug("get key: {} lock success! -- {} 毫秒", new Object[]{this.key, Long.valueOf(TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - nanoTime))});
}
}
lock 默认你的时间30s,
redisService.setIfAbsent(this.key, this.key)
进一步来看setIfAbsent的源码:
public Boolean setIfAbsent(String key, Object value) {
return this.getRedisTemplate().opsForValue().setIfAbsent(key, value);
}
public Boolean setIfAbsent(K key, V value) {
final byte[] rawKey = this.rawKey(key);
final byte[] rawValue = this.rawValue(value);
return (Boolean)this.execute(new RedisCallback<Boolean>() {
public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
return connection.setNX(rawKey, rawValue);
}
}, true);
}
对 Redis setNX的这个方法,参考官方文档,判断key是否存在(1/0)
Return value
Integer reply, specifically:
1 if the key was set
0 if the key was not set
再往下看 redisService.expire 保证key 60s有效,足够执行业务代码,
执行往后,delete该key
1.Redis Lock的更多相关文章
- Redis Distributed lock
using StackExchange.Redis; using System; using System.Collections.Generic; using System.Linq; using ...
- python redis自带门神 lock 方法
redis 支持的数据结构比较丰富,自制一个锁也很方便,所以极少提到其原生锁的方法.但是在单机版redis的使用时,自带锁的使用还是非常方便的.自己有车还打啥滴滴顺风车是吧,本篇主要介绍redis-p ...
- redisLock redis分布式锁
redis-lock redis setnx cmmand java object condition queue 条件队列 retrycount 带有重试次数限制 object wait time ...
- redis实现分布式可重入锁
利用redis可以实现分布式锁,demo如下: /** * 保存每个线程独有的token */ private static ThreadLocal<String> tokenMap = ...
- 用redis实现分布式锁,秒杀案例(转)
分布式锁的简单实现代码: 需要的jar包: jedis-2.9.0.jar. commons-pool2-2.4.2.jar import java.util.List; import java.ut ...
- 基于 redis 的分布式锁实现 Distributed locks with Redis debug 排查错误
小结: 1. 锁的实现方式,按照应用的实现架构,可能会有以下几种类型: 如果处理程序是单进程多线程的,在 python下,就可以使用 threading 模块的 Lock 对象来限制对共享变量的同步访 ...
- Redis分布式锁的实现
前段时间,我在的项目组准备做一个类似美团外卖的拼手气红包[第X个领取的人红包最大],基本功能实现后,就要考虑这一操作在短时间内多个用户争抢同一资源的并发问题了,类似于很多应用如淘宝.京东的秒杀活动场景 ...
- 【Redis使用系列】使用Redis做防止重复提交
前言 在平时的开发中我们都需要处理重复提交的问题,避免业务出错或者产生脏数据,虽然可以通过前端控制但这并不是可以完全避免,最好的方式还是前后端均进行控制,这样的话就可以更有效,尽可能全面的去减少错误的 ...
- Redis实现分布式锁1
Jedis结合setNX方法实现分布式锁 public boolean lock(String key, int exprie) { try { exprie = exprie <= 0 ? 6 ...
随机推荐
- 详细讲解使用Sublime Text 3进行Markdown编辑和实时预览
所需安装的插件 Markdown Editing // Markdown编辑和语法高亮 Markdown Preview// Markdown导出html预览 LiveReload// 时时预览 安装 ...
- TypeError: Cannot assign to read only property 'exports' of object '#<Object>'
我的项目在mac上运行的很好,结果windows电脑,就一直报这个错误 解决方案: babel增加 @babel/plugin-transform-modules-commonjs 参考文章: htt ...
- 【linux】linux下java环境安装
1:下载jdk的包,通过ftp传到服务器 2:解压 tar zxvf jdk-8u181-linux-x64.tar.gz 3:环境配置 编辑配置文件: vim /etc/profile 在文件下插入 ...
- Java通过循环结构和switch实现简易计算器
Java通过循环结构和switch实现简易计算器 可以循环计算,通过调用函数本身来实现重新计算 package com.shenxiaoyu.method; import java.util.Scan ...
- mysql事务控制和锁定语句
MySQL 支持对 MyISAM 和 MEMORY 存储引擎的表进行表级锁定,对 BDB 存储引擎的表进行页级锁定,对 InnoDB 存储引擎的表进行行级锁定.默认情况下,表锁和行锁都是自动获得的,不 ...
- 深入理解JS:执行上下文中的this(二)
目录 序言 Function.prototype.bind() 方法 箭头函数 参考 1.序言 在 深入理解JS:执行上下文中的this(一) 中,我们主要深入分析全局环境和函数环境中函数调用的 th ...
- Java基本语法---标识符、变量、数据类型转换及进制
Java基本语法 标识符 标识符:凡事可以自己起名字的地方,都可以叫做标志符 标识符命名规则: 26个字母大小写,数字0-9,下划线_,美元符号$ 数字不能开头 不能使用关键字和保留字,但是可以包含 ...
- PHP AES加解密(兼容php5,php7)
最近在工作中负责对接API,对方要求对业务数据进行AES 算法(256,ECB,补码方式:PKCS5Padding)加密. 加密算法要求如下: 算法AES/ECB/PKCS5Padding 密钥长度2 ...
- day 7 while循环
#隐式布尔值: 0 none 空# 一.流程控制# 短路运算:偷懒原则,偷懒到哪个位置,就把当前位置的值返回# 为0# (10>3 and 10 and 0 and 10 )or( 10> ...
- Rocket - debug - dm registers
https://mp.weixin.qq.com/s/P48K17TyRoZC7xBMltbXKQ 简单介绍调试模块中每个寄存器的定义. 1. DMI_RegAddrs 记录DMI访问的各个寄存器的地 ...