一、redis分布式锁的基本命令
- setnx
- getset
- expire
- del
redis相关命令可参考我的另一篇文章:https://blog.csdn.net/voilet_bin/article/details/84072803
二、Redis分布式锁流程图
流程图很关键,一定要理解,可结合代码一起看:
import com.bin.common.Const;
import com.bin.util.PropertiesUtil;
import com.bin.util.RedisShardedPoolUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.redisson.api.RLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import javax.annotation.PreDestroy;
import java.util.concurrent.TimeUnit;
@Component
@Slf4j
public class ScheduleTask {
@PreDestroy
public void delLock(){ // 终止进程前,删除key释放锁,防死锁
RedisShardedPoolUtil.del(Const.REDIS_LOCK.DO_TASK_LOCK);
}
@Scheduled(cron="0 */1 * * * ?")
public void doTask(){
log.info("定时任务启动");
long lockTimeout = Long.parseLong(PropertiesUtil.getProperty("lock.timeout","5000"));
Long setnxResult = RedisShardedPoolUtil.setnx(Const.REDIS_LOCK.DO_TASK_LOCK,String.valueOf(System.currentTimeMillis()+lockTimeout));
if(setnxResult != null && setnxResult.intValue() == 1){
doThing(Const.REDIS_LOCK.DO_TASK_LOCK);
}else{
//未获取到锁,继续判断,判断时间戳,看是否可以重置并获取到锁
String lockValueStr = RedisShardedPoolUtil.get(Const.REDIS_LOCK.DO_TASK_LOCK);
if(lockValueStr != null && System.currentTimeMillis() > Long.parseLong(lockValueStr)){
String getSetResult = RedisShardedPoolUtil.getSet(Const.REDIS_LOCK.DO_TASK_LOCK,String.valueOf(System.currentTimeMillis()+lockTimeout));
//再次用当前时间戳getset。
//返回给定的key的旧值,->旧值判断,是否可以获取锁
//当key没有旧值时,即key不存在时,返回nil ->获取锁
//这里我们set了一个新的value值,获取旧的值。
if(getSetResult == null || (getSetResult != null && StringUtils.equals(lockValueStr,getSetResult))){
//真正获取到锁
doThing(Const.REDIS_LOCK.DO_TASK_LOCK);
}else{
log.info("没有获取到分布式锁:{}",Const.REDIS_LOCK.DO_TASK_LOCK);
}
}else{
log.info("没有获取到分布式锁:{}",Const.REDIS_LOCK.DO_TASK_LOCK);
}
}
log.info("定时任务结束");
}
private void doThing(String lockName){
RedisShardedPoolUtil.expire(lockName,5);//有效期50秒,防止死锁
log.info("获取{},ThreadName:{}",Const.REDIS_LOCK.DO_TASK_LOCK,Thread.currentThread().getName());
int hour = Integer.parseInt(PropertiesUtil.getProperty("close.order.task.time.hour","2"));
// 执行业务逻辑
// dosometing ...
RedisShardedPoolUtil.del(Const.REDIS_LOCK.DO_TASK_LOCK);
log.info("释放{},ThreadName:{}",Const.REDIS_LOCK.DO_TASK_LOCK,Thread.currentThread().getName());
log.info("===============================");
}
}