redis实现分布式锁

Redis 分布式锁实现
代码示例
import redis.clients.jedis.JedisPool;
public class RedisLock {
private static final String LOCK_SUCCESS = "OK";
private static final String SET_IF_NOT_EXIST = "NX";
private static final String SET_WITH_EXPIRE_TIME = "PX";
private static final Long RELEASE_SUCCESS = 1L;
private JedisPool pool;
public RedisLock(JedisPool pool) {
this.pool = pool;
}
/**
* 尝试获取分布式锁
* @param lockKey 锁 比如user_id
* @param requestId 请求标识 比如 uuid
* @param expireTime 超期时间
* @return 是否获取成功
*/
public boolean tryDistributedLock(String lockKey, String requestId, int expireTime) {
String result = pool.getResource().set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);
if (LOCK_SUCCESS.equals(result)) {
return true;
}
return false;
}
/**
* 释放分布式锁
* @param lockKey 锁 比如 user_id
* @param requestId 请求标识 获取所的时候的uuid
* @return 是否释放成功
*/
public boolean releaseDistributedLock(String lockKey, String requestId) {
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
Object result = pool.getResource().eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));
if (RELEASE_SUCCESS.equals(result)) {
return true;
}
return false;
}
}
Lua脚本的作用
首先满足setnx + expire
的原子性,然后引入了Lua脚本,也是为保证删除操作的原子性。首先获取锁对应的value值,检查是否与requestId
相等,如果相等则删除锁(解锁)。那么为什么要使用Lua语言来实现呢?因为要确保上述操作是原子性的。
简单来说,就是在eval
命令执行Lua代码的时候,Lua代码将被当成一个命令去执行,并且直到eval
命令执行完成,Redis才会执行其他命令。