使用Redis实现分布式锁最简单的方案是在获取锁之前先查询一下以该锁为key对应的value存不存在,如果存在,则说明该锁被其他客户端获取了,否则的话就尝试获取锁,获取锁的方法很简单,只要以该锁为key,设置一个随机的值就行了。比如,我们有一批任务需要由多个分布式线程处理,每个任务都有一个taskId,为了保证每个任务只被执行一次,在工作线程执行任务之前,先获取该任务的锁,锁的key可以为taskId。因此,获取锁的过程可以用如下伪代码实现:
function boolean getLock(taskId){
if(taskId!=null){
return false
}
setKey(taskId);
return true;
}
坑一:
获取锁完了需要及时释放锁,所以我们将在finally块中加入释放锁,即便出现异常也能顺利释放掉,伪代码如下:
boolean lock =false;
tyr{
lock=getLock(taskId);
if(lock){
doSomething();//业务逻辑
}
}finally{
if(lock){
releaseLock(taskId);
}
}
坑二:获取锁以后服务器宕机等原因无法释放锁怎么办,这时候需要加入锁的失效时间
function boolean getLock(taskId,timeout){
return setKeyOnlyIfNotExists(taskId,timeout);
}
坑三:高并发下其他线程释放了当前线程的锁,需要加入随机数保证当前线程只能被当前线程释放锁
function void releaseLock(taskId,random_value){
if(getKey(taskId)==random_value){
deleteKey(taskId);
}
}
坑四:锁加入失效时间,但是这个时间不方便设置为固定值,所以解决思路是每次加锁成功以后新开一个定时任务,每隔1/3时间查看锁是否存在,如果存在即延时,保证业务逻辑正常执行完,这种思路目前可以使用redisson来解决
redissonLock.lock(leaseTime,TimeUnit.SECONDS);