分布式锁
分布式锁其实可以理解为:控制分布式系统有序的去对共享资源进行操作,通过互斥来保持一致性。
分布式锁的实现方式
1、基于数据库的乐观锁实现分布式锁
2、基于zookeeper 临时节点的分布式锁
3、基于redis的分布式锁(常用)
分布式锁的注意事项
1、互斥性:在任意时刻,只有一个客户端能持有锁
2、同一性:加锁和解锁必须是同一个客户端,客户端自己不能把别人加的锁给解锁
3、可重入性:即使有一个客户端在持有锁的期间奔溃而没有主动解锁,也能保证后续其他客户端能加锁
工具
public class RedisUtils {
private static int port = 6379;
private static String host = "127.0.0.1";
private static JedisPool pool;
static {
JedisPoolConfig config = new JedisPoolConfig();
config.setMinIdle(5);
pool = new JedisPool(config, host, port);
}
public static Jedis getJedis() {
return pool.getResource();
}
/**
* 分布式锁的实现方式
* 1、基于数据库的乐观锁实现分布式锁
* 2、基于zookeeper 临时节点的分布式锁
* 3、基于redis的分布式锁(常用)
* 分布式锁的注意事项
* 互斥性:在任意时刻,只有一个客户端能持有锁
* 同一性:加锁和解锁必须是同一个客户端,客户端自己不能把别人加的锁给解锁
* 可重入性:即使有一个客户端在持有锁的期间奔溃而没有主动解锁,也能保证后续其他客户端能加锁
*/
/**
* 获取分布式锁
* 方式1
* 使用redis的set命令实现获取分布式锁
* @param lockKey
* @param requestId
* @param timeout
* @return
*/
public static boolean getLock(String lockKey, String requestId, int timeout) {
// 获取Jedis对象,负责和远程redis服务器进行连接
Jedis jedis = getJedis();
// 参数三:NX和XX,
// 参数sin:EX和PX
String result = jedis.set(lockKey, requestId, "NX", "EX", timeout);
if (result == "OK") {
return true;
}
return false;
}
/**
* 方式2
* 使用 setnx 命令实现
* @param lockKey
* @param requestId
* @param timeout
* @return
*/
public static synchronized boolean getLock2(String lockKey, String requestId, int timeout) {
// 获取Jedis对象,负责和远程redis服务器进行连接
Jedis jedis = getJedis();
Long result = jedis.setnx(lockKey, requestId);
if (result == 1) {
// 设置有效期
jedis.expire(lockKey, timeout);
return true;
}
return false;
}
/***
* 释放分布式锁的代码
* 方式1
* del命令实现
* @param lockKey
* @param requestId
*/
public static void releaseLock(String lockKey, String requestId) {
// 获取Jedis对象,负责和远程redis服务器进行连接
Jedis jedis = getJedis();
if (requestId.equals(jedis.get(lockKey))) {
jedis.del(lockKey);
}
}
/**
* 方式2
* redis + lua 脚本实现 推荐
* @param lockKey
* @param requestId
* @return
*/
public boolean releaseLock2(String lockKey, String requestId) {
Jedis jedis = getJedis();
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));
if (result.equals(1L)) {
return true;
}
return false;
}
}