Redis实现分布式锁思路
常用的是redis函数是setnx(),这个应该是实现分布式锁最主要的函数。首先是将某一业务标识名作为键存到redis里,并为其设个过期时间,如果是还有加锁请求过来,先是通过setnx()看看是否能将锁的标识插入到redis里,可以的话就返回true,不可以就返回false。
一、使用Lua脚本简单的实现Redis锁的实现 :
public class DistributeLocker {
private Jedis jedis;
private Lock lock;
/**
* 加锁成功标识
*/
private static final String LOCK_SUCCESS = "1";
/**
* 脚本入参个数
*/
private static final int KEY_COUNT = 1;
/**
* 加锁脚本
*/
private static String LOCK_SCRIPT;
/**
* 解锁脚本
*/
private static String RELEASE_SCRIPT;
/**
* 初始化脚本
*/
static {
LOCK_SCRIPT = "local key = redis.call('get',KEYS[1]) if ('1' == key) then return 0 "
+ "else redis.call('set',KEYS[1],'1') redis.call('expire',KEYS[1],ARGV[1]) return 1 end";
RELEASE_SCRIPT = "if (redis.call('exists',KEYS[1])) then redis.call('del',KEYS[1]) end";
}
/**
* 定义带参构造函数
*/
public DistributeLocker (Lock lock) { }
public void lock (final String key, final int exprieTime) {
try {
if (LOCK_SUCCESS.equals(jedis.eval(LOCK_SCRIPT, KEY_COUNT, key, String.valueOf(exprieTime)))) {
lock.success();
} else {
lock.failure();
}
} finally {
releaseLock(key);
}
}
/**
* 解锁逻辑
*/
public void releaseLock (String key) {
jedis.eval(RELEASE_SCRIPT, KEY_COUNT, key);
}
}
public interface Lock {
void success();
void failure();
}
public class Test {
void purchase(String key, int secondTime){
new DistributeLocker(new Lock() {
@Override
public void success() {
// do something
}
@Override
public void failure() {
// do something
}
}).lock(key,secondTime);
}
}
注:Redis分布式锁的实现方式有很多种,各有利弊,加锁的时候主要注意检查锁与加锁操作要有原子性,防止重复加锁成功。过期时间主要是为了防止未释放锁导致锁的一直存在,从而无法获取锁操作。
二、使用Redisson框架
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.13.0</version>
</dependency>
-
使用缺省配置
-
工具类
@Slf4j
@Component
public class DistributeLocker {
private RedissonClient redissonClient;
public DistributeLocker(RedissonClient redissonClient) {
this.redissonClient = redissonClient;
}
public void lock (String key, long exprieTime, LockTask task) {
lock(0L, key, exprieTime, task);
}
public void lock (long waitTime, String key, long exprieTime, LockTask task) {
RLock rLock = redissonClient.getLock(key);
try {
if (rLock.tryLock(waitTime, exprieTime, TimeUnit.MILLISECONDS)) {
task.success();
} else {
task.failure();
}
} catch (Exception e) {
log.error("DistributeLocker.lock Error. key:{}, e:{}", key, e);
} finally {
rLock.unlock();
}
}
}
- 使用
@SpringBootApplication
@EnableDiscoveryClient
public class StartUpApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(StartUpApplication.class, args);
DistributeLocker locker = context.getBean(DistributeLocker.class);
locker.lock("test", 100L, new LockTask() {
@Override
public void success() {
System.out.println("加锁成功");
}
@Override
public void failure() {
System.out.println("加锁失败");
}
});
}
}