ScheduledExecutor和DelayQueue,Java任务延迟执行的秘密

本文探讨了Java中ScheduledExecutorService如何实现任务延迟执行,对比了Timer的缺陷,重点分析了ScheduledThreadPoolExecutor的DelayQueue工作原理,包括其如何确保线程不被阻塞、延迟时间的准确性以及周期任务的执行方式。通过源码解析,阐述了ScheduledFutureTask在延迟队列中的角色和任务调度的细节。
摘要由CSDN通过智能技术生成

引言

Timer类的解析中提到,Timer类的缺陷:

  1. 单线程
  2. Timer只有一个任务执行线程,如果某个TimerTask耗时较久,影响其他任务
  3. Timer不会捕获执行TimerTask时所抛出的异常,由于Timer是单线程,所以一旦出现异常,则线程就会终止,其他任务也得不到执行。
  4. 系统时间敏感性,由于Timer中使用了currentTimeMillis做参考,所以系统时间变化会使得任务发生变化

所以在JDK1.5后大家就抛弃了Timer,一般使用ScheduledThreadPoolExecutor。

研究完ScheduledExecutor,我突然发现一直困扰我的一个问题——程序中的定时任务是如何实现的?例如,闹钟。ScheduledExecutor正是一个绝佳的例子:
● 任务调度和任务执行解耦,并运行在不同线程上,防止阻塞。任务调度单线程即可满足性能要求,它并不是瓶颈
● 具备延迟时间的任务,在时间的维度上,可以假想它们排成一列,所以你不需要轮询所有任务,只需要关注最早开始的任务
● 等待并不需要轮询,可以等待指定时间唤醒

概述

我们已经看过Timer的延迟执行方案——任务放入最小堆中,任务线程每次取出需要最早执行的任务,并在当前线程中执行。
ScheduledThreadPoolExecutor简单来说,是基于线程池的实现基础上,把原有的任务队列换成DelayQueue。
所以我认为,核心其实在DelayQueue上,它是一种阻塞队列,只有当任务到指定延迟时间时,它才能返回;其次,它也是一种优先队列,基于数组的最小堆实现,按延迟时间排序。
由于取出任务之后,交给线程池执行(由线程池管理子线程执行),所以并不会阻塞调度线程,所以也就没有上述1,2,3的问题。而且它内部使用了nanoTime而不是currentTimeMillis,因而也和系统时间无关(nanoTime的区别是,它是计算从某一个时间的累计时间,这个时间是在启动JVM时任意指定的,例外,它的精度为微纳秒)。
所以它本身不复杂,线程池的实现参考之前的文章。

源码解析

API

ScheduledFuture<?> scheduleAtFixedRate(Runnable command,**long **initialDelay,**long **period,TimeUnit unit),指定任务,初始延迟时间,周期时间,时间单位。注意该方法每一周期启动一次任务,不需要等任务结束。
scheduleWithFixedDelay(Runnable command,**long **initialDelay,**long **delay,TimeUnit unit),指定任务,初始延迟时间,延迟时间,时间单位。注意该延迟时间指的是前一个周期结束到下一个周期开始时间,换句话说,它需要任务执行完才能开始下一个周期。

代码结构

请添加图片描述

ScheduledThreadPoolExecutor继承了ThreadPoolExecutor,复用线程池的功能。实现了ScheduledExecutorService,拓展为调度的线程池服务。

public interface ScheduledExecutorService extends ExecutorService {
   

    public ScheduledFuture<?> schedule(Runnable command,
                                       long delay, TimeUnit unit);

    public <V> ScheduledFuture<V> schedule(Callable<V> callable,
                                           long delay, TimeUnit unit);

    public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
                                                  long initialDelay,
                                                  long period,
                                                  TimeUnit unit);
    
    public ScheduledFuture<?
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值