Java中有那些定时任务的实现方式,下面从java原生和spring封装对动态管理定时任务的实现简单的聊一聊,不涉及外部组件的实现方式。
java.util包下提供了对定时任务的支持,涉及2个类:
使用该定时任务我们需要继承TimerTask抽象类,覆盖run方法编写任务执行代码,并利用Timer定时器对TimerTask进行调度。
Timer提供了多种方法,可分为一次性任务和可重复执行任务。
一次性任务是指Timer执行一次之后,该任务后续不再执行,包括2个方法:
可重复执行任务是指任务允许按照设定的规则重复执行,包括4个方法:
public class DownloadTimerTask extends TimerTask {
@Override
public void run() {
System.out.println("指定时间的任务操作内容");
}
}
public static void main(String[] args) throws ParseException {
// Timer执行周期任务基于绝对时间,会受到系统时间的影响
Timer timer = new Timer();
TimerTask downloadTimerTask = new DownloadTimerTask();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
Date date = simpleDateFormat.parse("2023-03-21 10:16:00");
timer.schedule(downloadTimerTask,date);
}
在idea中会看到”使用ScheduledExecutorService代替Timer吧 “提示,可见并不推荐使用Timer来实现定时任务。
java.util.concurrent包下提供了基于线程池设计的定时任务类ScheduledExecutorService,它的每个调度任务都会分配到线程池中的一个线程去执行,并发不受影响,各自执行各自的。
ScheduledExecutorService提供了3种方法:
实例:
public static void main(String[] args) {
// ScheduledThreadPoolExecutor基于相对时间,不会受到系统时间的影响
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);
//ScheduledExecutorService scheduledExecutorServicePool = new ScheduledThreadPoolExecutor(5, r -> new Thread(r, "executor-service-pool-" + r.hashCode()));
TimerTask downloadTimerTask = new DownloadTimerTask();
// 延迟5min后,运行且仅仅运行一次task
scheduledExecutorService.schedule(downloadTimerTask, 5, TimeUnit.MINUTES);
}
jdk原生的两个常用线程池对象:ThreadPoolExecutor、ScheduledThreadPoolExecutor。
ScheduledThreadPoolExecutor继承自ThreadPoolExecutor,主要用来在给定的延迟之后运行任务,或者定期执行任务。ScheduledThreadPoolExecutor的功能与Timer类似,但ScheduledThreadPoolExecutor功能更强大、更灵活。Timer对应的是单个后台线程,而 ScheduledThreadPoolExecutor可以在构造函数中指定多个对应的后台线程数。
ThreadPoolExecutor构造方法及其作用:
ScheduledThreadPoolExecutor构造方法及其作用:
实例见第2小节,ScheduledThreadPoolExecutor是接口ScheduledExecutorService的实现类。
springboot自动装配的两个常用线程池对象:ThreadPoolTaskExecutor,ThreadPoolTaskScheduler(参考org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration),分别对应jdk的两个线程池,是静态代理增强,故ThreadPoolTaskScheduler的api是最丰富的。
ThreadPoolTaskScheduler是spring中提供的线程池任务调度类,能够开启线程池进行任务调度。
ThreadPoolTaskScheduler 提供了4种定时任务方法:
ThreadPoolTaskScheduler.schedule()方法会创建一个定时计划ScheduledFuture,在这个方法需要添加两个参数,Runnable(线程接口类) 和CronTrigger(定时任务触发器),在ScheduledFuture中有一个cancel可以停止定时任务。
实例:
@Configuration
public class ThreadPoolTaskSchedulerConfig {
@Bean
public ThreadPoolTaskScheduler syncScheduler() {
ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
threadPoolTaskScheduler.setPoolSize(5);
threadPoolTaskScheduler.setRemoveOnCancelPolicy(true);
threadPoolTaskScheduler.setThreadNamePrefix("syncThread-");
return threadPoolTaskScheduler;
}
}
@Slf4j
public abstract class AbstractJob implements Runnable {
private ScheduledFuture> scheduledFuture;
@Autowired
private ThreadPoolTaskScheduler threadPoolTaskScheduler;
@Override
public void run() {
begin();
execute();
end();
}
/**
* 定时任务执行之前
*/
public void begin() {
log.info("------开始执行任务------");
}
/**
* 执行任务
*/
public abstract void execute();
/**
* 定时任务执行之后
*/
public void end() {
log.info("------结束执行任务------");
}
/**
* @description: 创建定时任务
* @param: cron 时间表达式
* @return: void
*/
public void createJob(String cron) {
try {
log.info("创建定时任务");
scheduledFuture = threadPoolTaskScheduler.schedule(this, new CronTrigger(cron));
} catch (Exception e) {
log.error("创建定时任务失败!");
e.printStackTrace();
}
}
/**
* 取消执行任务
*/
public void cancelJob() {
try {
if (scheduledFuture != null) {
scheduledFuture.cancel(true);
}
log.info("取消执行任务!");
} catch (Exception e) {
log.error("取消执行失败 !");
e.printStackTrace();
}
}
}