Java延时任务执行 -Timer/ScheduledThreadPoolExecutor实现

编程教程 > Java (48) 2025-01-22 09:15:48

概述

Timer/ScheduledThreadPoolExecutor都是是JDK提供的api

 

Timer Demo

import lombok.extern.slf4j.Slf4j;

import java.util.Timer;
import java.util.TimerTask;

@Slf4j
public class TimerDemo {
    public static void main(String[] args) {
        Timer timer = new Timer();
        log.info("--- 提交延时任 ---");
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                log.info("--- 执行延迟任务 ---");
            }
        },5000);
    }
}
Java延时任务执行 -Timer/ScheduledThreadPoolExecutor实现_图示-0a5f80e5213e40cab7232bffce9d6093.png
执行结果

执行结果与预期一致

Java延时任务执行 -Timer/ScheduledThreadPoolExecutor实现_图示-85d6501baab243a69a384300de1aed35.png
调用的schedule方法参考

timer实现延时任务原理

Java延时任务执行 -Timer/ScheduledThreadPoolExecutor实现_图示-20481c9f7d9a45b7bf1ab6bc4d05863f.png

 

  • TimerTask内部有一个nextExecutionTime属性,代表下一次任务执行的时间,在提交任务的时候会计算出nextExecutionTime值。
  • Timer内部有一个TaskQueue对象,用来保存TimerTask任务的,会根据nextExecutionTime来排序,保证能够快速获取到最早需要被执行的延迟任务。
  • 在Timer内部还有一个执行任务的线程TimerThread,这个线程就跟DelayQueue demo中开启的线程作用是一样的,用来执行到了延迟时间的任务。

所以总的来看,Timer有点像整体封装了DelayQueue demo中的所有东西,让用起来简单点。

虽然Timer用起来比较简单,但是在阿里规范中是不推荐使用的,主要是有以下几点原因:

  • Timer使用单线程来处理任务,长时间运行的任务会导致其他任务的延时处理
  • Timer没有对运行时异常进行处理,一旦某个任务触发运行时异常,会导致整个Timer崩溃,不安全

由于Timer在使用上有一定的问题,所以在JDK1.5版本的时候提供了ScheduledThreadPoolExecutor,这个跟Timer的作用差不多,并且他们的方法的命名都是差不多的,但是ScheduledThreadPoolExecutor解决了单线程和异常崩溃等问题。

ScheduledThreadPoolExecutor

 

Demo

@Slf4j
public class ScheduledThreadPoolExecutorDemo {

    public static void main(String[] args) {
        ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(
                5,
                new ThreadPoolExecutor.CallerRunsPolicy()
        );
        log.info("--- 提交延时任务 ---");
        executor.schedule(() -> log.info("--- 执行延时任务 ---") ,5, TimeUnit.SECONDS);
    }
}

拒绝策略new ThreadPoolExecutor.CallerRunsPolicy()参考:

Java线程池ThreadPoolExecutor常见拒绝策略RejectedExecutionHandler详解

Java延时任务执行 -Timer/ScheduledThreadPoolExecutor实现_图示-719213cebe3547c3813d1a5e38066dd6.png
执行结果

执行结果从时间来看与预期结果一致。

实现原理

ScheduledThreadPoolExecutor继承了ThreadPoolExecutor,也就是继承了线程池,所以可以有很多个线程来执行任务。

ScheduledThreadPoolExecutor在构造的时候会传入一个DelayedWorkQueue阻塞队列,所以线程池内部的阻塞队列是DelayedWorkQueue。

Java延时任务执行 -Timer/ScheduledThreadPoolExecutor实现_图示-937fb312fb104223bbcb786f58390990.png

在提交延迟任务的时候,任务会被封装一个任务会被封装成ScheduledFutureTask对象,然后放到DelayedWorkQueue阻塞队列中。

Java延时任务执行 -Timer/ScheduledThreadPoolExecutor实现_图示-5bc2ec1883354c188b7861917d92e5c7.png

 

ScheduledFutureTask实现了前面提到的Delayed接口,所以其实可以猜到DelayedWorkQueue会根据ScheduledFutureTask对于Delayed接口的实现来排序,所以线程能够获取到最早到延迟时间的任务。

当线程从DelayedWorkQueue中获取到需要执行的任务之后就会执行任务。

 


评论
User Image
提示:请评论与当前内容相关的回复,广告、推广或无关内容将被删除。

相关文章
概述Timer/ScheduledThreadPoolExecutor都是是JDK提供的api Timer Demoimport lombok.extern.s
DelayQueue 简介DelayQueue是JDK提供的api,是一个延迟队列DelayQueue泛型参数得实现Delayed接口,Delayed继承了Co
java编程中​​​​​​​通过Timer配合TimeTask实现计划调度任务的使用
Spring Boot定时任务阻塞解决方式一:修改定时任务的线程数量修改spring boot项目的application配置文件,将下面的配置修改为合适的值,默认1表示所有定时任务都是一个线程...
在这篇文章中,我们将讨论有关使用异步任务执行程序功能在不同线程中执行任务的Spring boot异步执行支持。我们将看看在Spring项目中配置SimpleAsyncTaskExecutor,C...
Spring框架自带了一个任务调度器,虽然默认的方式只能通过配置写死,但是也可以自己适当运用
问题描述最近写JavaFX程序遇到了下面的错误:Exception in thread "pool-2-thread-1" java.lang.IllegalStateException: No...
Java编程之Spring Cloud Hystrix Circuit熔断/断路
问题描述idea启动maven的JavaFX项目报错:Exception in Application start method java.lang.reflect.InvocationTarg...
Java 9 模块化编程
学习使用Spring Batch分区使用多个线程来处理Spring Boot应用程序中的一系列数据集任务。1.并行处理和分区1.1 并行处理 大多数批处理问题可以使用单线程解决,但很少有复杂的场...
每个Java学习者都会遇到10 + 1个常见错误,java 初学者常见十大潜在错误
学习使用Java配置创建Spring批处理作业(具有多个步骤)。 它使用Spring Boot 2,Spring batch 4和H2数据库来执行批处理作业。
Spring Boot MQTT协议通过spring boot整合apache artemis实现Java语言MQTT协议通信,搭建MQTT服务器可以参考上一篇 MQTT Java入门-搭建MQ...