SpringBoot Redis分布式锁的正确实现方式(5)
导读:SpringBoot,加锁 tryLock、lock tryLock 以阻塞等待 waitTime 时间的方式来尝试获取锁。获取成功则返回 true,反之 false。 tryAcquire 方法相当于执行了 Redis 的 SET resourceName u
SpringBoot
加锁 tryLock、lock
tryLock以阻塞等待waitTime时间的方式来尝试获取锁。获取成功则返回 true,反之 false。tryAcquire方法相当于执行了 Redis 的SET resourceName uuid:threadID NX PX {leaseTime}指令。
与tryLock不同的是,lock一直尝试自旋阻塞等待获取分布式锁,直到获取成功为止。而tryLock只会阻塞等待waitTime时间。
此外,为了让程序更加健壮,不念实现了阻塞等待获取分布式锁,让你用的更加开心,面试不慌加薪不难。如果你不需要自旋阻塞等待获取锁,那把 while 代码块删除即可。
@Override
public boolean tryLock(long waitTime, long leaseTime, TimeUnit unit) throws InterruptedException {
long time = unit.toMillis(waitTime);
long current = System.currentTimeMillis();
long threadId = Thread.currentThread().getId();
// 获取锁
Boolean isAcquire = tryAcquire(leaseTime, unit, threadId);
// lock acquired
if (Boolean.TRUE.equals(isAcquire)) {
return true;
}
time -= System.currentTimeMillis() - current;
// 等待时间用完,获取锁失败
if (time <= 0) {
return false;
}
// 自旋获取锁
while (true) {
long currentTime = System.currentTimeMillis();
isAcquire = tryAcquire(leaseTime, unit, threadId);
// lock acquired
if (Boolean.TRUE.equals(isAcquire)) {
return true;
}
time -= System.currentTimeMillis() - currentTime;
if (time <= 0) {
return false;
}
}
}
@Override
public void lock(long leaseTime, TimeUnit unit) {
long threadId = Thread.currentThread().getId();
Boolean acquired;
do {
acquired = tryAcquire(leaseTime, unit, threadId);
} while (Boolean.TRUE.equals(acquired));
}
private Boolean tryAcquire(long leaseTime, TimeUnit unit, long threadId) {
return redisTemplate.opsForValue().setIfAbsent(resourceName, getRequestId(threadId), leaseTime, unit);
}
解锁unlock
解锁的逻辑是通过执行 lua 脚本实现。
@Override
public void unlock() {
long threadId = Thread.currentThread().getId();
// 执行 lua 脚本
DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>(LuaScript.unlockScript(), Long.class);
Long opStatus = redisTemplate.execute(redisScript, keys, getRequestId(threadId));
if (opStatus == null) {
throw new IllegalMonitorStateException("attempt to unlock lock, not locked by current thread by node id: "
+ id + " thread-id: " + threadId);
}
}
LuaScript
其实这个脚本就是在讲解青铜板分布式锁原理的那段代码,具体逻辑已经解释过,这里就不再重复分析。
public class LuaScript {
private LuaScript() {
}
/**
* 分布式锁解锁脚本
*
* @return 当且仅当返回 `1`才表示加锁成功.
*/
public static String unlockScript() {
return "if (redis.call('exists', KEYS[1]) == 0) then " +
"return nil;" +
"end; "+
"if redis.call('get',KEYS[1]) == ARGV[1] then" +
" return redis.call('del',KEYS[1]);" +
"else" +
" return 0;" +
"end;";
}
}
相关阅读
-
b2b推广网站有哪些 垂直b2b电商平台推荐
跟大家聊一聊b2b推广网站有哪些和垂直b2b电商平台推荐方面的内容,下面小编为您详细解答 最近,很多小伙伴都反馈给我。我想知道哪些B2B网站在市场上做得很好。以下是IT袋网小编收集的全
-
前端开发工程师是做什么的 web前端的工作内容
IT袋网为大家说一说前端开发工程师是做什么的和web前端的工作内容方面的讲解,请看下面详细的介绍。 随着Internet的发展和多个终端的普及,前端开发工程师逐渐受到欢迎,但是前端开发工程
-
什么是Ceph 有什么特点?
如果想了解什么是CephIT技巧方面的经验,相关内容具体如下: 概述 Ceph是当前非常流行的开源分布式存储系统,具有高扩展性、高性能、高可靠性等优点,同时提供 块存储服务 (rbd)、 对象存储
-
[网络工程师]-网络规划与设计-通信规范分析
相对于大多数人[网络工程师]-网络规划与设计-通信规范分析方面的介绍,下面为详细的介绍。 在网络分析和设计过程中,通信规范分析处于第二个阶段,通过分析网络通信流量和通信模式,发


