前言
上篇文章介绍了Java中锁的应用,在SpringBoot单体应用中完全够用,但是SpringCloud微服务集群中就力所不及了。
我的使用场景是某些微服务应用中使用spring注解的形式来完成定时任务的功能,服务集群之后每台服务器都会调起定时任务,这和预想的不一样,需要添加分布式锁来控制任务的执行,推荐大家使用quartz和xxl-job来完成定时任务的调度。
一、redis
redis的使用我就不过多介绍了,前面文章写了好几篇了,可以自行爬楼翻看。
@Service
public class StudentService {
private static final Logger log = LoggerFactory.getLogger(StudentService.class);
@Autowired
StringRedisTemplate stringRedisTemplate;
@Value("${server.port}")
private String port;
@Scheduled(cron = "0 0/1 6-23 * * ?")
public void execute(){
ValueOperations<String, String> operations = stringRedisTemplate.opsForValue();
String key="student-"+ DateUtils.format(new Date(),"yyyyMMdd");
String value = RandomUtil.randomNumbers(6);
long timeout=24 * 60 * 60;
Boolean absent = operations.setIfAbsent(key, value, timeout, TimeUnit.SECONDS);
log.debug(port+"获取锁:"+absent);
try {//todo 业务处理
if(absent){
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
if(value.equals(operations.get(key))){
stringRedisTemplate.delete(key);
log.debug(port+"执行完成,解除锁");
}
}
}
}
定时任务集群要保证服务器时间一致,否则每次执行都可能跑到时间较为靠前的那台服务器上
二、Redisson
1.引入库
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.23.0</version>
</dependency>
2. 分布式锁
@Service
public class StudentService {
private static final Logger log = LoggerFactory.getLogger(StudentService.class);
@Value("${server.port}")
private String port;
@Autowired
private RedissonClient redissonClient;
@Scheduled(cron = "0 0/1 6-23 * * ?")
public void redisson(){
String key="student-"+ DateUtils.format(new Date(),"yyyyMMdd");
long timeout=24 * 60 * 60;
RLock lock = redissonClient.getLock(key);
boolean tryLock=false;
try {
tryLock = lock.tryLock();
log.debug(port+"获取锁["+key+"]:"+tryLock);
if(tryLock){
lock.lock(timeout, TimeUnit.SECONDS);//锁到期自动解锁
//todo 业务处理
Thread.sleep(10000);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
if(tryLock&&lock.isHeldByCurrentThread()){
lock.unlock();
log.debug(port+"执行完成,解除锁["+key+"]");
}
}
}
}
3. 锁自动续期
@Service
public class StudentService {
private static final Logger log = LoggerFactory.getLogger(StudentService.class);
@Value("${server.port}")
private String port;
@Autowired
private RedissonClient redissonClient;
@Scheduled(cron = "0 0/1 6-23 * * ?")
public void redissonRenewal(){
String key="student-"+ DateUtils.format(new Date(),"yyyyMMdd");
long time=10;
RLock lock = redissonClient.getLock(key);
boolean tryLock=false;
try {
tryLock = lock.tryLock(time,TimeUnit.SECONDS);
log.debug(port+"获取锁["+key+"]:"+tryLock);
if(tryLock){
log.debug(port+"锁["+key+"]剩余生存时间为:"+(lock.remainTimeToLive()/1000)+"秒");
lock.lock();
//todo 业务处理
Thread.sleep(40000);
log.debug(port+"锁["+key+"]剩余生存时间为:"+(lock.remainTimeToLive()/1000)+"秒");
}
} catch (Exception e) {
e.printStackTrace();
}finally {
if(tryLock&&lock.isHeldByCurrentThread()){
lock.unlock();
log.debug(port+"执行完成,解除锁["+key+"]");
}
}
}
}