
1.默认固定执行定时任务的服务
在某一台服务上面执行定时任务,其他服务关闭定时任务,或者在定时任务前加判断指定ip,缺点指定的服务出现问题则定时任务无法在运行。
2.利用mysql共享锁事务管理机制运行任务
创建定时任务表,name为不同定时任务的指定名称,excute为是否执行中 1执行0未执行
由于存在表锁和行锁,因此同一时刻只能有一个事务操作,可以保证只执行一次。
此处更新操作只会成功一次,执行完重新设置excute为0;
//基于mysql
@Scheduled(cron = "0 * * * * ?")
public void test1() throws UnknownHostException {
boolean test = timingService.lambdaUpdate()
.set(TimingB::getExcute, "1")
.set(TimingB::getIp, InetAddress.getLocalHost().getHostAddress())
.eq(TimingB::getName, "test")
.eq(TimingB::getExcute,"0")
.update();
if (test==true){
System.out.println("-----------定时任务开始执行------------");
//...业务
//重新设置回0
timingService.lambdaUpdate()
.set(TimingB::getExcute, "0")
.eq(TimingB::getName, "test").update();
}
}
3.利用redis
执行定时任务前先查询 redis 是否有改任务的值,没有就自己 执行,并插入新的 key-value。有的话则不执行。
//基于redis
@Scheduled(cron = "0 * * * * ?")
public void test2() {
//先走分布式锁
boolean b = getLock("b", 5000, 10, 1000);
//获得锁在判断
if (b){
String test = template.opsForValue().get("test");
if (test==null){
//定时任务为1分钟,过期时间设置50为秒
template.opsForValue().set("test","test",50000L, TimeUnit.MILLISECONDS);
System.out.println("-----------定时任务开始执行------------");
//...业务
}
}
}
public boolean getLock(String lock, long timeout, long tryInterval, long lockExpireTime) {
try {
long startTime = System.currentTimeMillis();
do{
if (template.opsForValue().setIfAbsent(lock, lock, lockExpireTime, TimeUnit.MILLISECONDS)) {
return true;
} else {//存在锁
log.debug("lock is exist!!!");
}
if (System.currentTimeMillis() - startTime > timeout) {//尝试超过了设定值之后直接跳出循环
return false;
}
Thread.sleep(tryInterval);
}
while (template.hasKey(lock)) ;
} catch (InterruptedException e) {
log.error(e.getMessage());
return false;
}
return false;
}
4.使用分布式任务调度框架
如Quartz、Xxl-job、Elastic-job等等。