赞
踩
官方github网站:https://github.com/redisson/redisson
Redisson官网:https://redisson.org/
pom.xml
文件中写入
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.13.6</version>
</dependency>
以上方法根据需要选其一即可,此处采用方法三
import org.redisson.Redisson; import org.redisson.api.RedissonClient; import org.redisson.config.Config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class RedissonConfig { @Bean public RedissonClient redissonClient() { // 配置类 Config config = new Config(); // 添加redis地址,这里添加了单点的地址,也可以使用config.useClusterServers()添加集群地址 config.useSingleServer().setAddress("redis://192.168.88.66:6379") .setPassword("123456"); // 创建客户端 return Redisson.create(config); } }
// 创建锁对象
RLock lock = redissonClient.getLock("lock:order:" + userId);
// 尝试获取锁
boolean isLock = lock.tryLock();
// 判断是否成功
if (!isLock) {
// 获取失败返回错误
}
try {
// 执行对应的业务
} finally {
// 释放锁
lock.unlock();
}
其中trylock
方法共有三个重载方法,如果使用无参的方法,则不会进行等待,锁失效时间使用默认值(应该是30s)。
trylock(long waitTime, long leaseTime, TimeUnit unit)可以去设置等待时间、锁失效时间、时间单位。
trylock(long time, TimeUnit unit) 设置等待时间,时间单位。
可重入:利用hash结构记录线程id和重入次数
可重试:利用信号量和PubSub功能实现等待、唤醒,获取锁失败的重试机制
超时续约:利用watchDog,每隔一段时间(releaseTime/3),重置超时时间
Redisson实现也是使用的Lua脚本,具体Redisson实现方法,大家可以去写一个model看下解码的Redisson源码。以下Lua脚本是和Redisson源码思路一样的,但不完全一致,可以帮助理解原理。
-- Redisson 可重入锁获取锁的原理 local key = KEYS[1]; -- 锁的key local threadId = ARGV[1]; -- 线程唯一标识 local releaseTime = ARGV[2]; -- 锁的自动释放时间 -- 判断是否存在 if(redis.call('exists', key) == 0) then -- 不存在, 获取锁 redis.call('hset', key, threadId, '1'); -- 设置有效期 redis.call('expire', key, releaseTime); return 1; -- 返回结果 end; -- 锁已经存在,判断threadId是否是自己 if(redis.call('hexists', key, threadId) == 1) then -- 存在, 获取锁,重入次数+1 redis.call('hincrby', key, threadId, '1'); -- 设置有效期 redis.call('expire', key, releaseTime); return 1; -- 返回结果 end; return 0; -- 代码走到这里,说明获取锁的不是自己,获取锁失败
-- Redisson可重入锁的删除锁原理 local key = KEYS[1]; -- 锁的key local threadId = ARGV[1]; -- 线程唯一标识 local releaseTime = ARGV[2]; -- 锁的自动释放时间 -- 判断当前锁是否还是被自己持有 if (redis.call('HEXISTS', key, threadId) == 0) then return nil; -- 如果已经不是自己,则直接返回 end; -- 是自己的锁,则重入次数-1 local count = redis.call('HINCRBY', key, threadId, -1); -- 判断是否重入次数是否已经为0 if (count > 0) then -- 大于0说明不能释放锁,重置有效期然后返回 redis.call('EXPIRE', key, releaseTime); return nil; else -- 等于0说明可以释放锁,直接删除 redis.call('DEL', key); return nil; end;
主从一致性:设置连锁multiLock,多个独立的Redis节点,必须在所有节点都获取重入锁,才算获取锁成功
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。