锁的处理
- 单应用中使用锁:单进程多线程
使用 synchronized 或 Lock 实现该场景下的锁机制 - 分布式应用中使用锁:多进程
分布式锁的实现方式
- 数据库的乐观锁
- 基于zookeeper的分布式锁
- 基于redis的分布式锁
分布式锁的注意事项
- 互斥性:在任意时刻,只有一个客户端能持有锁
- 同一性:加锁和解锁必须是同一个客户端,客户端自己不能把别人加的锁给解了
- 避免死锁:即使有一个客户端在持有锁的期间奔溃而没有主动解锁,也能保证后续其他客户端能加锁
实现分布式锁
在SET命令中,有很多可选项可以用来修改命令的行为。以下是SET命令可用选项的基本语法
SET KEY VALUE [EX seconds] [PX milliseconds] [NX|XX]
EX seconds
:设置指定的到期时间(单位:秒)PX milliseconds
:设置指定的到期时间(以毫秒为单位)NX
:仅在键不存在时设置键XX
只有在键已存在时才设置
获取锁
方式一:使用redis的set命令实现获取分布式锁
//lockKey:锁
//requestId:请求ID,保证同一性
//expireTime:过期时间,避免死锁
private static Jedis jedis=new Jedis("",6379);
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;
}
方式二:使用sexnx命令实现分布式锁
public static boolean getLock2(String lockKey,String requestId,int expireTime){
Long setnx = jedis.setnx(lockKey, requestId);
if(setnx==1){
//这里破坏了原子性,可能有点问题
jedis.expire(lockKey, expireTime);
return true;
}
return false;
}
释放锁
del命令实现
public static void releaseLock(String lockKey,String requestId){
if(requestId.equals(jedis.get(lockKey))){
jedis.del(lockKey);
}
}