1、方式一
使用redission的特性来控制集群部署时的多次调用
缺点:单机的程序会在此处等待,导致其他任务没办法执行,原因是@Scheduled默认是单线程调度的
// 启动延时30秒执行,之后每隔60秒执行一次
@Scheduled(initialDelay = 30 * 1000, fixedDelay = 60 * 1000)
public void scheduledSync() {
RLock lock = redissonClient.getLock(KEY);
if (lock.tryLock()) {
try {
} catch (Exception e) {
} finally {
lock.unlock();
}
}
}
1.1、方式一可配置@Scheduled的多线程调用模式
@Bean
public TaskScheduler taskScheduler() {
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
taskScheduler.setPoolSize(10);
return taskScheduler;
}
2、方式二
使用线程池的特性来解决本次任务已执行完成,不耽误程序调度其他任务的执行;由于@Scheduled默认是单线程调度的,长时间占用此任务的话,其他任务都没法调用
// 自定义线程池,参数含义:
// 一个核心线程;
// 最大是一个线程;
// 线程回收空闲时间间隔零秒;
// 使用阻塞队列,队列最大存放任务量为一个;
// 在线程数已满、队列已满的情况下采取丢弃队列中旧的任务
ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0, TimeUnit.SECONDS, new LinkedBlockingQueue(1), new ThreadPoolExecutor.DiscardOldestPolicy());
// 启动延时30秒执行,之后每隔60秒执行一次
@Scheduled(initialDelay = 30 * 1000, fixedDelay = 60 * 1000)
public void scheduledMethod() {
executor.submit(() -> {
try {
int pageNo = 1;
int pageSize = 50;
List<Object> list;
do {
PageHelper.startPage(pageNo++, pageSize, false);
list = selectData();
list.foreach(obj->execMechod(obj));
} while (!list.isEmpty() && list.size() >= pageSize);
} catch (Exception e) {
log.error("", e);
}
});
}
3、调度执行的方法
public void execMechod(Object obj) {
RLock lock = redissonClient.getLock(KEY + obj.getId());
if (lock.tryLock()) {
try {
// 是否需要再次验证数据状态
int count = updateStatusData();
if (count == 1) {
// TODO 执行后续代码
}
} catch (Exception e) {
log.error("", e);
} finally {
lock.unlock();
}
}
}