1. 单机定时任务
java.util.Timer
是 JDK 1.3 开始就已经支持的一种定时任务的实现方式。
TimerTask task = new TimerTask() {
public void run() {
System.out.println("当前时间: " + new Date() + "n" + 线程名称: " + Thread.currentThread().getName());
}
};
System.out.println("当前时间: " + new Date() + "n" + 线程名称: " + Thread.currentThread().getName());
Timer timer = new Timer("Timer");
long delay = 1000L;
timer.schedule(task, delay);
一个 Timer
一个线程,这就导致 Timer
的任务的执行只能串行执行,一个任务执行时间过长的话会影响其他任务(性能非常差),再比如发生异常时任务直接停止(Timer
只捕获了 InterruptedException
)。
2. ScheduledExecutorService
ScheduledExecutorService
是一个接口,有多个实现类,比较常用的是 ScheduledThreadPoolExecutor
。
TimerTask repeatedTask = new TimerTask() {
@SneakyThrows
public void run() {
System.out.println("当前时间: " + new Date() + "n" + 线程名称: " + Thread.currentThread().getName());
}
};
System.out.println("当前时间: " + new Date() + "n" + 线程名称: " + Thread.currentThread().getName());
ScheduledExecutorService executor = Executors.newScheduledThreadPool(3);
long delay = 1000L;
long period = 1000L;
executor.scheduleAtFixedRate(repeatedTask, delay, period, TimeUnit.MILLISECONDS);
Thread.sleep(delay + period * 5);
executor.shutdown();
3. Spring task
@Scheduled(cron = "1 * * * * ? ")
使用一个标签即可实现定时任务,支持Cron表达式,但是Spring 自带的定时调度只支持单机,并且提供的功能比较单一。
4. 时间轮
时间轮是一个环形的队列(底层一般基于数组实现),队列中的每一个元素(时间格)都可以存放一个定时任务列表。常见的实现有Kafka、Dubbo、Zookeeper ... 时间轮比较适合任务数量比较多的定时任务场景,它的任务写入和执行的时间复杂度都是 0(1)
5. 分布式定时任务技术
Quartz
可以说是 Java 定时任务领域的老大哥或者说参考标准,不支持UI,可以使用quartzui实现,且具有较多的系统入侵性代码。