1.锁的处理
- 单应用中(单进程多线程情况)锁的处理:
- synchronized
- lock
- 分布式应用中锁的处理:
- 数据库乐观锁;
- 基于zookeeper的分布式锁;
- 基于redis的分布式锁
2.分布式锁需要注意事项
- 互斥性: 在任意时刻,只有一个客户端能持有锁
- 同一性: 加锁和解锁必须是同一个客户端,客户端自己不能把别的客户端加的锁给解了
-
避免死锁: 即使有一个客户端在持有锁的期间崩溃而没有主动解锁,也能保证后续其他客户端能加锁
3.获取锁
方式一:使用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;
}
方式二:使用setnx命令,这里使用synchronized保证方法的原子性
1 public static synchronized boolean Lock2(String lockKey,String requestId,int expireTime) { 2 Long result = jedis.setnx(lockKey, requestId); 3 if(result == 1) { 4 jedis.expire(lockKey, expireTime); 5 return true; 6 } 7 8 return false; 9 }
4.释放锁
方式一:使用del命令
/** * 释放分布式锁 * @param lockKey * @param requestId */ public static void releaseLock(String lockKey,String requestId) { if (requestId.equals(jedis.get(lockKey))) { jedis.del(lockKey); } }
方式二:使用Lua脚本
public static boolean releaseLock(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 = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId)); if (result.equals(1L)) { return true; } return false; }