当前位置: 首页 > news >正文

【并发编程】聊聊定时任务ScheduledThreadPool的实现原理和源码解析

ScheduledThreadPoolExecutor 是在线程池的基础上 拓展的定时功能的线程池,主要有四种方式,具体可以看代码,
这里主要描述下

  • scheduleAtFixedRate : 除了第一次执行的时间,后面任务执行的时间 为 time = MAX(任务执行时间,每次等待时间) 取最大值
  • scheduleWithFixedDelay:除了第一次执行的时间,后面任务的时间为 任务执行时间+每次等待时间。
    在这里插入图片描述

使用案例

		// 创建一个定时任务线程池
		ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1);
        
        // 延迟1S后执行
        executor.schedule(() -> {}, 1000, TimeUnit.MILLISECONDS);

		// 立马执行
        executor.execute(() -> {
            System.out.println("execute");
        });

		// 第一次延迟1S,之后每3S执行一次,如果任务时间超过3S,那么等任务执行后执行下一次任务
        executor.scheduleAtFixedRate(() -> {
            try {
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("at"+new Date());
        }, 1000, 3000, TimeUnit.MILLISECONDS);

		// 第一次延迟1S执行。任务执行完成后+3S 执行下一次任务
        executor.scheduleWithFixedDelay(() -> {
            try {
                TimeUnit.SECONDS.sleep(5);
                System.out.println("with"+new Date());
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        },1000, 3000, TimeUnit.MILLISECONDS);

源码解析

其实主要就是把握ScheduledFutureTask 和 线程池的核心流程的类就可以。

ScheduledFutureTask

在这里插入图片描述
在这里插入图片描述

DelayedWorkQueue

本质是一个二叉树形式的堆结构,会将邻近执行时间的任务排在前面。

schedule 方法分析

整体的流程其实就是 封装定时任务,然后触发延迟执行。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

delayedExecute

在这里插入图片描述
在这里插入图片描述

ScheduledFutureTask.run方法

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

流程图

这里来简单描述下整体的流程
1.先将任务封装成一个任务 ScheduledFutureTask, 根据线程池状态判断是否执行或者删除任务
2.将任务添加到延迟队列中
3.根据线程池配置 看是否创建线程执行任务。
4.运行的线程不断从延迟队列中获取任务执行。

其实本质就是利用线程池复用机制 + 延迟队列 实现定时任务。

在这里插入图片描述

总结

ScheduledThreadPoolExecutor和ThreadPoolExecutor的区别:

  • ThreadPoolExecutor每次addwoker就会将自己的Task传进新创建的woker中的线程执行,因此woker会第一时间执行当前Task,只有线程数超过了核心线程才会将任务放进队列里
  • ScheduledThreadPoolExecutor是直接入队列,并且创建woker时传到woker的是null,说明woker中的线程刚启动时并没有任务执行,只能通过getTask去队列里取任务,取任务时会判断是否到了执行时间,因此具有了延时执行的特性,并且task执行完了,会将当前任务重新放进堆里,并设置下次执行的时间。

相关文章:

  • java字符串
  • 【Linux】线程同步与互斥
  • 如何在PHP爬虫中处理异常情况的详细指南
  • unsigned类型与signed类型的区别介绍
  • NAS和网盘可以同步吗?
  • requestAnimationFrame 和定时器的含义,使用场景及区别
  • Unity AI 技术浅析(二)
  • C#程序加密与解密Demo程序示例
  • 计算机毕业设计SpringBoot+Vue.js智能家居系统(源码+文档+PPT+讲解)
  • 如何对数据库进行备份
  • 链表双指针经典习题
  • 为什么要开源?
  • lsblk命令linux查询设备信息
  • 深度学习入门指南
  • while-经典面试题实战
  • c++ 类成员指针及其与`std::bind`交互使用的简单说明
  • 使用 Docker 部署 BaGet 并推送 NuGet 包
  • 前端小食堂 | Day10 - 前端路由の时空裂隙
  • Java是值传递还是引用传递
  • 特征选择之特征重要性排序(基于树模型)
  • 做前端网站用什么软件写代码/深圳网络营销推广专员
  • 空间做网站/驻马店网站seo
  • 网站建设什么公司好/百度一下官方入口
  • 沙河做网站/线上推广渠道主要有哪些
  • 株洲新闻网红网株洲站/google搜索引擎入口下载
  • 网站开发文档模板下载/免费建网站知乎