Redis实现分布式锁
锁的处理
- 单应用中使用锁:单进程多线程
synchronize、Lock
- 分布式应用中使用锁:多进程
分布式锁的实现方式
- 数据库的乐观锁
- 基于zookeeper的分布式锁
- 基于redis的分布式锁
分布式锁的注意事项
- 互斥性:在任意时刻,只有一个客户端能持有锁
- 同一性:加锁和解锁必须是同一个客户端,客户端自己不能把别人加的锁给解了。
- 避免死锁:即使有一个客户端在持有锁的期间崩溃而没有主动解锁,也能保证后续其他客户端能加锁。(可以使用过期时间等方式处理)
实现分布式锁
添加maven依赖
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
获取锁
对key进行赋值,有值表示处于锁状态,否则表示没有被锁;这里value可以存放requestId值,用于区分是哪个客户端进行加锁
jedis为jar中的链接redis资源方法,多种连接方式这里不详细讲解
方式1(使用set命令实现):
/**
* 使用redis的set命令实现获取分布式锁
* @param lockKey 可以就是锁
* @param requestId 请求ID,保证同一性
* @param expireTime 过期时间,避免死锁
* @return
*/
public static boolean getLock(String lockKey,String requestId,int expireTime) {
//NX:保证互斥性
String result = jedis.set(lockKey, requestId, "NX", "EX", expireTime);
if("OK".equals(result)) {
return true;
}
return false;
}
方式2(使用setnx命令实现):
setnx命令:但key不存在时进行赋值,当key存在时,不进行操作
public static boolean getLock(String lockKey,String requestId,int expireTime) {
Long result = jedis.setnx(lockKey, requestId);
if(result == 1) {
//设置过期时间,避免死锁
jedis.expire(lockKey, expireTime);
return true;
}
return false;
}
释放锁
方式1(del命令实现):
/**
* 释放分布式锁
* @param lockKey
* @param requestId
*/
public static void releaseLock(String lockKey,String requestId) {
if (requestId.equals(jedis.get(lockKey))) {
jedis.del(lockKey);
}
}