记录一下实现定时任务的几个方式:
1.使用线程池
主要是通过 newScheduledThreadPool 类类实现定时任务的线程池,下面贴一个示例代码:
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ScheduledTaskExample {
public static void main(String[] args) {
// 创建线程池
ScheduledExecutorService executor = Executors.newScheduledThreadPool(5);
// 延迟1秒后开始执行任务
executor.schedule(new Runnable() {
@Override
public void run() {
// 在这里编写你要执行的定时任务代码
System.out.println("执行定时任务");
}
}, 2, TimeUnit.SECONDS);
// 等待一段时间后关闭线程池
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
executor.shutdown();
}
}
在上述示例中,ScheduledExecutorService
类提供了用于创建定时任务的方法schedule()。该方法接受一个Runnable
对象和一个时间参数,时间参数表示延迟多久开始执行任务。TimeUnit.SECONDS
用于指定时间单位为秒。如果要执行间隔任务,把schedule()换成scheduleAtFixedRate()就行了,参数加多一个间隔时间参数,其余不变。
总结:
-
优点:
- 简单:使用Java自带的线程池类,无需引入额外的依赖。
- 轻量级:不需要额外的框架或组件,适用于简单的定时任务需求。
- 灵活性:可以自定义线程池的大小和参数,根据实际需求进行调整。
-
缺点:
- 任务管理较为简单:线程池一般只提供基本的任务管理功能,如定时执行、间隔执行等,对于更复杂的任务调度需求可能不够灵活。
2. Spring Task定时任务
首先在启动类上开启定时任务
@EnableScheduling
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;
@Component
public class MyTaskScheduler implements SchedulingConfigurer {
private final TaskScheduler taskScheduler;
private String cron; //动态修改此参数
@Autowired
public MyTaskScheduler(TaskScheduler taskScheduler) {
this.taskScheduler = taskScheduler;
}
//1.必须调用changeTaskExecutionTime()方法,修改cron之后定时任务才会生效
public void changeTaskExecutionTime() {
// 修改定时任务的执行时间
taskScheduler.schedule(() -> {
// 执行定时任务的逻辑
System.out.println("执行定时任务 1111");
}, new CronTrigger("0/2 * * * * ?")); // 修改为每2秒执行一次
}
//2.启动则生效,可以动态修改cron表达式
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.addTriggerTask(
()->{
System.out.println("执行定时任务 2222 ");
},new CronTrigger("0/2 * * * * ?")
);
}
}
注:
1. 此处要确保TaskScheduler的实例已经在应用程序的上下文中进行了配置,例如通过在另一个配置类中添加@Bean注解来创建和配置TaskScheduler的实例,例如:
在配置类里加上:
@Bean public TaskScheduler taskScheduler(){ // Spring提供的定时任务线程池类 ThreadPoolTaskScheduler taskScheduler=new ThreadPoolTaskScheduler(); //设定最大可用的线程数目 taskScheduler.setPoolSize(10); return taskScheduler; }
2. 确保在进行构造器注入时,有且只有一个符合条件的TaskScheduler实例存在,否则会导致注入失败或者出现歧义。
3. 第三方组件(Quartz)
首先,引入依赖
Gradle:
// https://mvnrepository.com/artifact/org.quartz-scheduler/quartz
implementation group: 'org.quartz-scheduler', name: 'quartz', version: '2.3.2'Maven:
<!-- https://mvnrepository.com/artifact/org.quartz-scheduler/quartz -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.2</version>
</dependency>
创建一个实现了Job接口的执行任务类,该类主要定义任务的执行逻辑 ,例如:
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
public class MyJob implements Job {
public void execute(JobExecutionContext context) throws JobExecutionException {
// 在这里定义你的任务逻辑
System.out.println("Hello, Quartz!");
}
}
然后创建一个调度器以及实现任务的触发器,触发器定义了任务何时执行的规则:
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
public class Main {
public static void main(String[] args) {
try {
// 创建调度器
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
// 定义一个任务
JobDetail job = JobBuilder.newJob(MyJob.class)
.withIdentity("myJob", "group1")
.build();
// 定义触发器
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("myTrigger", "group1")
.startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(10) // 每10秒执行一次
.repeatForever()) // 无限重复执行
.build();
// 将任务和触发器加入调度器
scheduler.scheduleJob(job, trigger);
// 启动调度器
scheduler.start();
// 等待一段时间,让任务执行
Thread.sleep(60000);
// 关闭调度器
scheduler.shutdown();
} catch (SchedulerException | InterruptedException e) {
e.printStackTrace();
}
}
}
注:下面是几种常见的定时执行方式:
1. SimpleTrigger(简单触发器):按照给定的时间间隔和重复次数执行任务。
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("myTrigger", "group1")
.startAt(startDate) // 指定任务开始时间
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(10) // 每10秒执行一次
.withRepeatCount(5)) // 总共执行5次
.build();
2. CronTrigger(Cron触发器):基于Cron表达式来定义任务的执行规则,可以实现更复杂的定时规则。
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("myTrigger", "group1")
.startAt(startDate) // 指定任务开始时间
.withSchedule(CronScheduleBuilder.cronSchedule("0/5 * * * * ?")) // 每5秒执行一次
.build();
3. DailyTimeIntervalTrigger(每日时间间隔触发器):在每天指定的时间段内重复执行任务。
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("myTrigger", "group1")
.startAt(startDate) // 指定任务开始时间
.withSchedule(DailyTimeIntervalScheduleBuilder.dailyTimeIntervalSchedule()
.startingDailyAt(TimeOfDay.hourAndMinuteOfDay(9, 0)) // 每天9:00开始
.endingDailyAt(TimeOfDay.hourAndMinuteOfDay(17, 0)) // 每天17:00结束
.onDaysOfTheWeek(MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY) // 仅在周一至周五执行
.withIntervalInMinutes(30)) // 每30分钟执行一次
.build();
如果需要动态修改任务执行时间,则需要创建一个新的触发器来替换旧触发器,重新调度任务:
// 修改触发器的执行时间
TriggerKey triggerKey = new TriggerKey("myTrigger", "group1");
SimpleTrigger newTrigger = (SimpleTrigger) TriggerBuilder.newTrigger()
.withIdentity(triggerKey)
.startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(5) // 每5秒执行一次
.repeatForever())
.build();
scheduler.rescheduleJob(triggerKey, newTrigger);