/**
* @Description: 基于Redis的分布式锁 使用条件:jedis。
* @Author Chase Lou
* @Date 2019/7/24 19:26
**/
@Component
public class RedisLock {
private final Logger log = LoggerFactory.getLogger(RedisLock.class);
/**
* 默认获取锁超时时间是5秒
*/
private final long defaultGetTimeOut = 5000;
/**
* 默认锁过期时间5
*/
private final long defaultExpire = 5000;
private final LockProcessor lockProcessor =
(jedisCommands, resource, secretKey, expire) ->
jedisCommands.set(RedisKeyConstants.LOCKS + resource, secretKey, "NX", "PX", expire);
private final UnlockProcessor unlockProcessor =
(jedisCommands, resource, secretKey) -> {
if (secretKey.equals(jedisCommands.get(RedisKeyConstants.LOCKS + resource))) {
return jedisCommands.del(RedisKeyConstants.LOCKS + resource).longValue() == 1L;
}
return false;
};
@Autowired
StringRedisTemplate stringRedisTemplate;
public String tryLock(String resource) throws RedisLockTimeOutException {
return tryLock(resource, defaultGetTimeOut, defaultExpire);
}
public String tryLock(String resource, long expire) throws RedisLockTimeOutException{
return tryLock(resource, defaultGetTimeOut, expire);
}
public String tryLock(String resource, long getTimeOut, long expire) throws RedisLockTimeOutException{
return lock(resource, getTimeOut, expire, false);
}
public String directLock(String resource) {
return directLock(resource, defaultExpire);
}
public String directLock(String resource, long expire) {
return lock(resource, -1, expire, false);
}
public String blockLock(String resource) {
return blockLock(resource, defaultExpire);
}
public String blockLock(String resource, long expire) {
return lock(resource, -1, expire, true);
}
/**
* 获取redis锁
*
* @param resource 被锁的资源名称
* @param getTimeOut 获取锁超时时间,负数表示不会超时,只会尝试一次
* @param expire 锁最长时间,将在该时间后自动释放锁
* @param waitingOnSuccess 是否一直等待到获取成功
* @return todo 返回值类型应该更有意义
*/
private String lock(String resource, long getTimeOut, long expire, boolean waitingOnSuccess) throws RedisLockTimeOutException{
if (StringUtils.isEmpty(resource)) {
throw new RedisLockNoResourceException(String.format("请求上锁的资源[%s]不合法,请保证资源不为空", resource));
}
long currentTimeMillis = System.currentTimeMillis();
String secretKey = String.format("%s%s%s,Expires after %s millisecond", resource, currentTimeMillis, Math.random(), expire);
log.info("获取[{}]的redis锁:开始尝试", resource);
do {
String execute = stringRedisTemplate.execute((RedisCallback<String>) connection ->
lockProcessor.apply((JedisCommands) connection.getNativeConnection(), resource, secretKey, expire));
//如果执行成功execute等于"OK"
if (!StringUtils.isEmpty(execute)) {
log.info("获取[{}]的redis锁:成功,耗时[{}]ms", resource, System.currentTimeMillis() - currentTimeMillis);
return secretKey;
}
try {
Thread.sleep(10);
} catch (InterruptedException e) {
log.error(String.format("获取[{}]的redis锁:线程异常", resource), e);
Thread.currentThread().interrupt();
}
} while (waitingOnSuccess || (getTimeOut > 0 && System.currentTimeMillis() - currentTimeMillis < getTimeOut));
log.info("获取[{}]的redis锁:失败", resource);
if (getTimeOut > 0) {
throw new RedisLockTimeOutException(String.format("获取[%s]的redis锁超过获取时间[%s],请延长获取时间或者优化代码的处理速度", resource, getTimeOut));
}
return "";
}
/**
* 释放redis锁
*
* @param resource 被锁资源
* @param secretKey 锁秘钥,防止自己锁过期的时候,释放了其他人的锁
*/
public void unlock(String resource, String secretKey) {
if (StringUtils.isEmpty(resource) || StringUtils.isEmpty(secretKey)) {
throw new RedisUnlockNoResourceException(String.format("请求解锁的资源[%s]或者秘钥[%s]不合法,请保证资源或者秘钥不为空", resource, secretKey));
}
log.info("释放[{}]的redis锁:开始尝试", resource);
Boolean success =
stringRedisTemplate.execute((RedisCallback<Boolean>) connection -> unlockProcessor.apply((JedisCommands) connection.getNativeConnection(), resource, secretKey));
if (success) {
log.info("释放[{}]的redis锁:成功", resource);
} else {
log.info("释放[{}]的redis锁:失败", resource);
throw new RedisUnlockException(String.format("释放[%s]的redis锁失败,可能由于执行时间过长或者尝试释放不属于自己的锁。", resource));
}
}
@FunctionalInterface
private interface LockProcessor {
String apply(JedisCommands jedisCommands, String resource, String secretKey, long expire);
}
@FunctionalInterface
private interface UnlockProcessor {
boolean apply(JedisCommands jedisCommands, String resource, String secretKey);
}
}
```闲聊时刻
10年短信公司,互联网100强企业!主营业务:短信(国内和国际)App H5一键免密登录,防薅羊毛接口,图片OCR,空号检测,活跃号检测,人证核验,活体检测,高防ddos攻击等等200多个企业服务接口!需要的联系他13592366783 官方链接:https://zz.253.com/v5.html#/register?uid=1953
自己公司需求 偶然间 用了一家第三方接口供应商,产品应有尽有,很齐全,对接文档非常详细,彼此都很节约时间,主要非常稳定,包括服务方面很给力,有兴趣的博友,可以联系他,算是对合作伙伴的支持了