冰河技术
导读
♻学习路线
  • 面试必问系列

    • 面试必问
  • 架构与模式

    • Java极简设计模式
    • 实战高并发设计模式
  • Java核心技术

    • Java8新特性
    • IOC核心技术
    • JVM调优技术
  • 容器化核心技术

    • Dockek核心技术
  • 分布式存储

    • Mycat核心技术
  • 数据库核心技术

    • MySQL基础篇
  • 服务器核心技术

    • Nginx核心技术
  • 渗透核心技术

    • 渗透实战技术
  • 底层技术
  • 源码分析
  • 基础案例
  • 实战案例
  • 面试
  • 系统架构
  • Spring6核心技术
  • 分布式事务

    • 分布式事务系列视频
  • SpringBoot
  • SpringCloudAlibaba
  • 🔥AI大模型项目

    • 一站式AI智能平台
    • AI智能客服系统
    • AI智能问答系统
    • 实战AI大模型
  • 中间件项目

    • 手写高性能Redis组件
    • 手写高性能脱敏组件
    • 手写线程池项目
    • 手写高性能SQL引擎
    • 手写高性能Polaris网关
    • 手写高性能RPC项目
  • 高并发项目

    • 分布式IM即时通讯系统(新)
    • 分布式Seckill秒杀系统
    • 实战高并发设计模式
  • 微服务项目

    • 简易电商脚手架项目
  • 手撕源码

    • 手撕Spring6源码
🌍知识星球
  • 总览

    • 《书籍汇总》
  • 出版图书

    • 《深入理解高并发编程:核心原理与案例实战》
    • 《深入理解高并发编程:JDK核心技术》
    • 《深入高平行開發:深度原理&專案實戰》
    • 《深入理解分布式事务:原理与实战》
    • 《MySQL技术大全:开发、优化与运维实战》
    • 《海量数据处理与大数据技术实战》
  • 电子书籍

    • 《实战高并发设计模式》
    • 《深入理解高并发编程(第2版)》
    • 《深入理解高并发编程(第1版)》
    • 《从零开始手写RPC框架(基础篇)》
    • 《SpringCloud Alibaba实战》
    • 《冰河的渗透实战笔记》
    • 《MySQL核心知识手册》
    • 《Spring IOC核心技术》
  • 关于自己
  • 关于学习
  • 关于职场
B站
Github
导读
♻学习路线
  • 面试必问系列

    • 面试必问
  • 架构与模式

    • Java极简设计模式
    • 实战高并发设计模式
  • Java核心技术

    • Java8新特性
    • IOC核心技术
    • JVM调优技术
  • 容器化核心技术

    • Dockek核心技术
  • 分布式存储

    • Mycat核心技术
  • 数据库核心技术

    • MySQL基础篇
  • 服务器核心技术

    • Nginx核心技术
  • 渗透核心技术

    • 渗透实战技术
  • 底层技术
  • 源码分析
  • 基础案例
  • 实战案例
  • 面试
  • 系统架构
  • Spring6核心技术
  • 分布式事务

    • 分布式事务系列视频
  • SpringBoot
  • SpringCloudAlibaba
  • 🔥AI大模型项目

    • 一站式AI智能平台
    • AI智能客服系统
    • AI智能问答系统
    • 实战AI大模型
  • 中间件项目

    • 手写高性能Redis组件
    • 手写高性能脱敏组件
    • 手写线程池项目
    • 手写高性能SQL引擎
    • 手写高性能Polaris网关
    • 手写高性能RPC项目
  • 高并发项目

    • 分布式IM即时通讯系统(新)
    • 分布式Seckill秒杀系统
    • 实战高并发设计模式
  • 微服务项目

    • 简易电商脚手架项目
  • 手撕源码

    • 手撕Spring6源码
🌍知识星球
  • 总览

    • 《书籍汇总》
  • 出版图书

    • 《深入理解高并发编程:核心原理与案例实战》
    • 《深入理解高并发编程:JDK核心技术》
    • 《深入高平行開發:深度原理&專案實戰》
    • 《深入理解分布式事务:原理与实战》
    • 《MySQL技术大全:开发、优化与运维实战》
    • 《海量数据处理与大数据技术实战》
  • 电子书籍

    • 《实战高并发设计模式》
    • 《深入理解高并发编程(第2版)》
    • 《深入理解高并发编程(第1版)》
    • 《从零开始手写RPC框架(基础篇)》
    • 《SpringCloud Alibaba实战》
    • 《冰河的渗透实战笔记》
    • 《MySQL核心知识手册》
    • 《Spring IOC核心技术》
  • 关于自己
  • 关于学习
  • 关于职场
B站
Github
  • 第01部分:专栏介绍

    • 开篇:我要带你一次性彻底吃透线程池核心技术
  • 第02部分:线程池核心技术

    • 第01节:线程池核心原理技术解析
    • 第02节:线程池总体结构技术解析
    • 第03节:线程池执行任务的核心流程解析
    • 第04节:Worker线程核心执行流程解析
    • 第05节:线程池优雅关闭核心流程解析
    • 第06节:定时任务线程池核心技术解析
  • 第03部分:实战手写线程池

    • 实战:400行代码手写线程池
  • 第04部分:专栏总结

    • 总结:手写线程池专栏整体总结

《手写线程池》线程池核心技术-第06节:定时任务线程池核心技术解析

作者:冰河
星球:http://m6z.cn/6aeFbs
博客:https://binghe.site
文章汇总:https://binghe.site/md/all/all.html
源码获取地址:https://t.zsxq.com/0dhvFs5oR

沉淀,成长,突破,帮助他人,成就自我。

  • 本章难度:★★★☆☆
  • 本章重点:简单介绍定时任务线程池的核心执行流程,重点掌握ScheduledThreadPoolExecutor与Timer的区别、定时任务线程池的初始化、调度流程和优雅关闭流程。从全局视角掌握线程池的核心技术原理,学会融汇贯通,将线程池的编程思想灵活应用到自身实际项目中,提升实际项目的并发处理能力,以及自身的并发编程内功功底。

大家好,我是冰河~~

Java从JDK1.5版本开始提供了定时任务线程池,定时任务线程池的核心类就是ScheduledThreadPoolExecutor,从类结构上看,ScheduledThreadPoolExecutor类继承自ThreadPoolExecutor类,主要提供了定时任务线程池的功能,能够实现周期性的调度任务。

一、前言

上一节中,主要从源码角度深入分析了线程池优雅关闭的核心流程,重点对比分析了线程池中的shutdown()方法、shutdownNow()方法和awaitTermination()方法,以此深入解析线程池的优雅关闭流程。接下来,深入解析和探讨定时任务线程池。

二、本节诉求

简单介绍定时任务线程池的核心执行流程,重点掌握ScheduledThreadPoolExecutor与Timer的区别、定时任务线程池的初始化、调度流程和优雅关闭流程。从全局视角掌握线程池的核心技术原理,学会融汇贯通,将线程池的编程思想灵活应用到自身实际项目中,提升实际项目的并发处理能力,以及自身的并发编程内功功底。

三、ScheduledThreadPoolExecutor与Timer的区别

ScheduledThreadPoolExecutor类是从JDK1.5版本开始提供的定时任务线程池,而在JDK1.5版本之前实现定时任务主要使用的是Timer类和TimerTask类。接下来,就简单对比下Timer类与ScheduledThreadPoolExecutor类的区别。

3.1 线程实现的区别

在线程的实现方面,Timer类与ScheduledThreadPoolExecutor类是存在区别的。

(1)Timer类内部的实现是单线程模式,如果某个TimerTask任务的执行时间比较久,或者抛出了异常,会影响到其他任务的执行。

(2)ScheduledThreadPoolExecutor内部的实现是多线程模式,并且在线程池中线程是可以复用的,某个ScheduledFutureTask任务执行的时间比较久,不会影响到其他任务的调度执行。

3.2 系统时间区别

在获取系统时间层面,Timer类与ScheduledThreadPoolExecutor类对于时间的敏感程度不同。

(1)Timer内部是基于操作系统的绝对时间实现的,对于操作系统的时间绝对敏感,如果操作系统的时间发生变化,则Timer的线程调度不再准确。

(2)ScheduledThreadPoolExecutor类内部是基于相对时间实现的,操作系统时间的变化不会影响ScheduledThreadPoolExecutor对于线程的调度结果。

3.3 处理异常区别

Timer类与ScheduledThreadPoolExecutor类对于异常的处理方面存在区别。

(1)Timer类不会捕获异常,又因为Timer类内部是基于单线程实现的。所以,如果某个任务抛出异常,则其他任务也会受到影响不再执行。

(2)ScheduledThreadPoolExecutor类内部基于线程池调度任务,如果某个任务抛出异常后,其他任务仍会正常执行。

3.4 任务编排区别

Timer类与ScheduledThreadPoolExecutor类对于任务的排序方面存在区别。

(1)Timer类内部不支持对于任务的排序。

(2)ScheduledThreadPoolExecutor类内部支持对于任务的排序功能。在ScheduledThreadPoolExecutor类的内部,定义了一个静态内部类DelayedWorkQueue,DelayedWorkQueue本质上是一个有序队列,支持对存储在DelayedWorkQueue队列中的任务按照距离下次执行时间间隔的大小进行排序。

3.5 任务优先级区别

Timer类与ScheduledThreadPoolExecutor类在任务执行的优先级上存在区别。

(1)Timer中执行的TimerTask任务没有优先级的概念,只是根据系统的绝对时间来触发任务的执行。

(2)ScheduledThreadPoolExecutor中执行的ScheduledFutureTask有优先级的概念。ScheduledFutureTask类实现了java.lang.Comparable接口和java.util.concurrent.Delayed接口。也就是说,ScheduledFutureTask类实现了java.lang.Comparable接口的compareTo()方法和java.util.concurrent.Delayed接口的getDelay()方法,可以根据这两个方法实现任务的优先级。

3.6 返回结果区别

Timer类与ScheduledThreadPoolExecutor类在返回结果方面存在区别。

(1)Timer中执行的TimerTask类只是实现了java.lang.Runnable接口,无法获取结果数据。

(2)ScheduledThreadPoolExecutor中执行的ScheduledFutureTask类继承了FutureTask,FutureTask类实现了Future接口,可以通过Future接口的get()方法获取返回的结果数据。

四、定时任务线程池的初始化

从类结构的角度来看,ScheduledThreadPoolExecutor类是ThreadPoolExecutor类的子类,主要在ThreadPoolExecutor类实现的线程池基础上实现了定时任务的功能。ScheduledThreadPoolExecutor类的初始化主要是通过构造方法实现的,ScheduledThreadPoolExecutor类的构造方法如下所示。

public ScheduledThreadPoolExecutor(int corePoolSize) {
	super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedWorkQueue());
}
public ScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory) {
	super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
		  new DelayedWorkQueue(), threadFactory);
}
public ScheduledThreadPoolExecutor(int corePoolSize, RejectedExecutionHandler handler) {
	super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
		  new DelayedWorkQueue(), handler);
}
public ScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
	super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
		  new DelayedWorkQueue(), threadFactory, handler);
}

从ScheduledThreadPoolExecutor类的构造方法的源码可以看出,ScheduledThreadPoolExecutor的构造方法本质上还是调用的ThreadPoolExecutor类的构造方法。

五、定时任务线程池的调度流程

从源码角度来看,ScheduledThreadPoolExecutor类中经过一系列方法的调用,最终实现了ScheduledThreadPoolExecutor类的调度流程。接下来,就对ScheduledThreadPoolExecutor类涉及到调度流程的核心方法进行简单的介绍。

5.1 schedule()方法解析

schedule()方法实现了延时执行一次任务的功能,在ScheduledThreadPoolExecutor类中,提供了两个schedule()方法,源码如下所示。

public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) {
	//如果传递的Runnable对象和TimeUnit时间单位为空,则直接抛出空指针异常
	if (command == null || unit == null)
		throw new NullPointerException();
	//封装任务对象,在decorateTask方法中直接返回ScheduledFutureTask对象
	RunnableScheduledFuture<?> t = decorateTask(command, 
	     new ScheduledFutureTask<Void>(command, null, triggerTime(delay, unit)));
	//执行延时任务
	delayedExecute(t);
	//返回任务
	return t;
}
public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) 
	//如果传递的Callable对象和TimeUnit时间单位为空,抛出空指针异常
	if (callable == null || unit == null)
		throw new NullPointerException();
	//封装任务对象,在decorateTask方法中直接返回ScheduledFutureTask对象
	RunnableScheduledFuture<V> t = decorateTask(callable,
		new ScheduledFutureTask<V>(callable, triggerTime(delay, unit)));
	//执行延时任务
	delayedExecute(t);
	//返回任务
	return t;
}

通过源码可以看出,ScheduledThreadPoolExecutor类中提供了两个重载的schedule()方法。两个schedule()方法中,只是第一个参数不同,一个方法是传递Runnable接口对象,另一个方法是传递Callable接口对象。

在schedule()方法的内部,会将传递进来的Runnable接口对象和Callable接口对象封装成RunnableScheduledFuture对象。而RunnableScheduledFuture对象本质上就是ScheduledFutureTask对象。将封装成的RunnableScheduledFuture对象,传入delayedExecute()方法中执行定时任务。

查看完整文章

加入冰河技术知识星球,解锁完整技术文章、小册、视频与完整代码

在 GitHub 上编辑此页
上次更新: 2026/5/2 00:42
Contributors: binghe001
Prev
第05节:线程池优雅关闭核心流程解析
阅读全文
×

扫码或搜索:冰河技术
发送:290992
即可立即永久解锁本站全部文章

星球会员
跳转链接