在 Java 里实现简单定时任务有多种方式,不同方式的原理也有所不同
- java.util.Timer 和 java.util.TimerTask
实现原理
Timer 类是 Java 提供的一个定时器工具,它内部持有一个任务队列和一个后台线程。TimerTask 是一个抽象类,代表一个可以被 Timer 执行的定时任务。当创建一个 Timer 对象时,它会启动一个后台线程,这个线程会不断地从任务队列中取出任务并执行。
任务调度:使用 Timer 的 schedule() 或 scheduleAtFixedRate() 等方法可以将 TimerTask 任务添加到任务队列中,并指定任务的执行时间和周期。Timer 会根据任务的执行时间对任务进行排序,保证先到期的任务先执行。
线程安全:Timer 内部的任务队列是线程安全的,因为 Timer 在操作任务队列时会进行同步处理,确保多线程环境下任务的正确调度。
import java.util.Timer;
import java.util.TimerTask;
public class TimerExample {
public static void main(String[] args) {
Timer timer = new Timer();
TimerTask task = new TimerTask() {
@Override
public void run() {
System.out.println("定时任务执行了,当前时间:" + System.currentTimeMillis());
}
};
// 延迟 1 秒后开始执行,每隔 2 秒执行一次
timer.schedule(task, 1000, 2000);
}
}
- ScheduledExecutorService
实现原理
ScheduledExecutorService 是 Java 并发包(java.util.concurrent)提供的一个接口,用于创建定时任务。它基于线程池的原理,内部维护了一个线程池来执行定时任务。相比于 Timer,ScheduledExecutorService 更加灵活和强大,因为它支持多线程并发执行任务,并且对异常的处理更加健壮。
任务调度:通过 ScheduledExecutorService 的 schedule()、scheduleAtFixedRate() 和 scheduleWithFixedDelay() 等方法可以将任务提交到线程池中,并指定任务的执行时间和周期。线程池会根据任务的调度规则,在合适的时间执行任务。
线程管理:ScheduledExecutorService 会自动管理线程的生命周期,包括线程的创建、销毁和复用。当任务执行完成后,线程会返回到线程池中等待下一个任务,提高了资源的利用率。
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ScheduledExecutorServiceExample {
public static void main(String[] args) {
ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
Runnable task = () -> System.out.println("定时任务执行了,当前时间:" + System.currentTimeMillis());
// 延迟 1 秒后开始执行,每隔 2 秒执行一次
executor.scheduleAtFixedRate(task, 1, 2, TimeUnit.SECONDS);
}
}
- Spring 的 @Scheduled 注解
实现原理
Spring 框架提供了 @Scheduled 注解来简化定时任务的开发。它基于 Spring 的 AOP(面向切面编程)和任务调度器实现。
AOP 代理:当在 Spring 管理的 Bean 中使用 @Scheduled 注解时,Spring 会使用 AOP 为该 Bean 创建一个代理对象。在代理对象中,会拦截被 @Scheduled 注解标记的方法,并根据注解中指定的调度规则进行任务调度。
任务调度器:Spring 内部使用 TaskScheduler 作为任务调度器,默认情况下使用 ThreadPoolTaskScheduler。TaskScheduler 会根据 @Scheduled 注解中的配置,将任务添加到任务队列中,并在合适的时间执行任务。
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class SpringScheduledTask {
@Scheduled(fixedRate = 2000) // 每隔 2 秒执行一次
public void executeTask() {
System.out.println("定时任务执行了,当前时间:" + System.currentTimeMillis());
}
}