【Java进阶篇】Java中Timer实现定时调度的原理(解析)

在这里插入图片描述

Java中Timer实现定时调度的原理

  • ✔️ 引言
  • ✔️JDK 中Timer类的定义
  • ✔️拓展知识仓
    • ✔️优缺点


✔️ 引言


Java中的Timer类是用于计划执行一项任务一次或重复固定延迟执行的简单工具。它使用一个名为TaskQueue的内部类来存储要执行的任务,这些任务被封装为TimerTask对象。

Timer实现定时调度的基本原理:

  1. 创建 Timer 对象:当你创建一个Timer对象时,它会实例化一个线程(不是守护线程),这个线程用于执行计划任务。
  2. 添加任务:你可以使用schedulescheduleAtFixedRate方法向Timer添加任务。这些方法接受一个TimerTask对象和一个延迟时间(以及可选的重复间隔)。
  3. 内部存储Timer内部使用一个优先级队列(具体是TaskQueue类)来存储要执行的任务。队列中的每个元素都是一个表示要执行的任务的TimerTask对象。队列根据任务的执行时间进行排序,以确保任务按照预定的时间顺序执行。
  4. 执行线程Timer类的线程在后台运行,并定期检查任务队列。当线程发现队列中有任务到达其预定的执行时间时,它会从队列中取出该任务并执行它。
  5. 处理重复任务:对于需要重复执行的任务,Timer会重新计算下一个执行时间,并将任务重新放入队列中。这样,当任务的下一次执行时间到达时,线程会再次从队列中取出并执行它。
  6. 取消任务:你可以使用Timer.cancel()方法来取消所有已调度的任务,或者使用TimerTask.cancel()方法来取消单个任务。取消的任务将从队列中移除,并且不会再次调度。
  7. 注意事项:虽然Timer在简单场景下可以很好地工作,但它并不是最适合所有场景的定时任务解决方案。特别是,在需要更复杂的调度需求或在并发环境中,使用ScheduledExecutorService可能是更好的选择。

总而言之,Java中的Timer类通过内部使用一个优先级队列来存储和管理定时任务,并通过一个单独的线程来检查和执行这些任务,从而实现了定时调度功能。


✔️JDK 中Timer类的定义


Java中的Timer类是一个定时调度器,用于在指定的时间点执行任务。JDK 中Timer类的定义如下:


public class Timer {
	
	/**
	*
	*     The timer task queue.This data structure is shared with the timer
	*     thread. The timer produces tasks, via its various schedule calls,
	*     and the timer thread consumes, executing timer tasks as appropriate,
	*     and removing them from the queue when they're obsolete.
	*/

	private final TaskOueue queue = new TaskOueue() ;

	/**
	*     The timer thread
	*/
	private final TimerThread thread = new TimerThread(queue);
}

以上就是 Timer 中最重要的两入成员变量:


1、TaskQueue: 一个任务队列,用于存储已计划的定时任务。任务队列按照任务的执行时间进行排序,确保最早执行的任务排在队列前面。在队列中的任务可能是一次性的,也可能是周期性的。


2、TimerThread : Timer 内部的后台线程,它负责扫描 TaskQueue 中的任务,检查任务的执行时间,然后在执行时间到达时执行任务的 run() 方法。TimerThread 是一个守护线程,因此当所有非守护线程完成时,它会随之终止。


任务的定时调度的核心代码就在TimerThread 中:


/**
*   @author xinbaobaba
*/

class TimerThread extends Thread {
	//标志位
	boolean newTasksMayBeScheduled = true;

	/**
	*    存储 TimerTask 的队列
	*/
	private TaskQueue queue ;
	
	TimerThread(TaskQueue queue) {
		this .queue = queue;
	}

	public void run() {
		try {
			mainLoop();
		} finally {
			synchronized (queue) {
				newTasksMayBeScheduled = false;
				queue.clear();
			}
		}
	}

	/**
	*    主要的计时器循环。
	*/

	private void mainLoop() {
		while (true) {
			try {
				TimerTask task;
				boolean taskFired;
				synchronized (queue) {
					//等待队列变为非空
					while (queue.isEmpty() && newTasksMayBeScheduled)
					queue .wait() ;
					if (queue.isEmpty())
						// 队列为空,将永远保持为空; 线程终止
						break;

					//队列非空;查看第一个事件并执行相应操作
					long currentTime, executionTime;
					task = queue .getMin();
					synchronized (task.lock) {
						if (task.state == TimerTask.CANCELLED) {
							queue .removeMin() ;
							//无需执行任何操作,再次轮询队列
							continue; 
						}
						currentTime = System.currentTimeMillis();
						executionTime = task.nextExecutionTime;
						if (taskFired = (executionTime <= currentTime)) {
							if (task.period == 0) {// 非重复,移除
								queue.removeMin);
								task.state = TimerTask.EXECUTED;
							} else {// 重复任务,重新安排
								queue.rescheduleMin(
									task.period <  ? currentTime   -   task.period : executionTime + task.period);
							}
						}
					}
					if (!taskFired)  // 任务尚未触发;等待
					queue .wait(executionTime - currentTime);
				}
				if (taskFired) // 任务触发;运行它,不持有锁
				task.run();
			} catch (InterruptedException e) {
			}
		}
	}
}

可以看到,TimerThread的实际是在运行mainLoop方法,这个方法一进来就是一个while(true)的循环,他在循环中不断地从TaskQueue中取出第一个任务,然后判断他是否到达执行时间了,如果到了,就触发任务执行。否则就继续等一会再次执行。


不断地重复这个动作,从队列中取出第一个任务进行判断,执行。。。


这样只要有新的任务加入队列,就在队列中按照时间排队,然后唤醒timerThread重新检查队列进行执行就可以了。代码如下:


private void sched(TimerTask task, long time, long period) {
	if (time < 0) {
		throw new IllegalArgumentException("Illegal execution time.");
	}
	// Constrain value of period sufficiently to prevent numeric
	// overflow while still being effectively infinitely large.
	if (Math.abs(period) > (Long.MAX VALUE >> 1))
		period >>= 1;


	synchronized(queue) {
		if (!thread.newTasksMayBeScheduled)
			throw new IllegalstateException("Timer already cancelled.");	
		
		synchronized(task.lock) {
			if (task.state != TimerTask.VIRGIN) 
				throw new IllegalstateException("Task already scheduled or cancelled");
			task.nextExecutionTime = time;
			task.period = period;
			
			task.state = TimerTask.SCHEDULED;
		}

		//新任务入队列
		queue.add(task);
		//唤醒任务
		if (queue.getMin() == task)
			queue .notify();
	}
}

✔️拓展知识仓


✔️优缺点


Timer 类用于实现定时任务,最大的好处就是他的实现非常简单,特别的轻量级,因为它是Java内置的,所以只需要简单调用就行了。


但是他并不是特别好的解决定时任务的方案,因为他存在以下问题:


1、Timer内部是单线程执行任务的,如果某个任务执行时间较长,会影响后续任务的执行


2、如果任务抛出未捕获异常,将导致整个 Timer 线程终止,影响其他任务的执行


3、Timer 无法提供高精度的定时任务。因为系统调度和任务执行时间的不确定性,可能导致任务执行的时间不准确


4、虽然可以使用 cancel 方法取消任务,但这仅仅是将任务标记为取消状态,仍然会在任务队列中占用位置,无法释放资源。这可能导致内存泄漏


5、当有大量任务时,Timer 的性能可能受到影响,因为它在每次扫描任务队列时都要进行时间比较


6、Timer执行任务完全基于JVM内存,一旦应用重启,那么队列中的任务就都没有了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/289081.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

小肥柴慢慢手写数据结构(C篇)(5-2 AVL树)

小肥柴慢慢学习数据结构笔记&#xff08;C篇&#xff09;&#xff08;5-2 AVL树 目录5-5 AVL出现的原因5-5-1 平衡树5-5-2 平衡二叉树的具体案例 5-6 AVL平衡策略的讨论5-7 不使用平衡因子的实现&#xff08;黑皮书&#xff0c;训练思维&#xff09;5-8 使用平衡因子的实现&…

【RocketMQ每日一问】RocketMQ SQL92过滤用法以及原理?

1.生产端 public class SQLProducer {public static int count 10;public static String topic "xiao-zou-topic";public static void main(String[] args) {DefaultMQProducer producer MQUtils.createLocalProducer();IntStream.range(0, count).forEach(i -&g…

管程-第三十五天

目录 为什么要引入管程 管程的定义和基本特征 用管程解决生产者消费者问题 结论 本节思维导图 为什么要引入管程 原因&#xff1a;在解决进程的同步与互斥问题时&#xff0c;信号量机制存在编写困难和易出错的问题 能不能设计一种机制&#xff0c;让程序员写程序时不再需…

从 YOLOv1 到 YOLO-NAS 的所有 YOLO 模型:论文解析

在计算机视觉的浩瀚领域&#xff0c;有一支耀眼的明星&#xff0c;她的名字传颂着革新与突破的传奇——YOLO&#xff08;You Only Look Once&#xff09;。回溯时光&#xff0c;走进这个引人注目的名字背后&#xff0c;我们仿佛穿越进一幅画卷&#xff0c;一幅展现创新魅力与技…

【elfboard linux开发板】4. 文件点灯与创建多进程

ps&#xff1a;提升效率的小tips&#xff1a; 灵活运用vim操作命令&#xff0c;gg快速跳转到文件开头&#xff0c;G跳转到结尾 多行操作 ctrl V shift i 插入修改内容 esc退出编辑 sudo vi /etc/vim/vimrc 在文件中添加如下内容省略重复工作&#xff1a; autocmd BufNewFile …

飞腾Ubantu22.04.3安装OpenNebula测试

1.概述 因OpenneBula官方镜像源只有AMD架构的镜像包不存在ARM的镜像包&#xff0c;借此用源码编译进行测试。 2.官网github地址 下载解压存放在服务器上&#xff1a; https://github.com/OpenNebula/minione/blob/master文件目录&#xff1a; 3.安装依赖包 sudo apt -y …

智慧农田使用的自动虫情测报灯的作用

TH-CQ3S随着科技的不断进步&#xff0c;智慧农业正在全球范围内兴起。作为智慧农业的重要组成部分&#xff0c;智慧农田已经成为提高农业生产效率、保障农产品质量安全的重要手段。而在智慧农田中&#xff0c;自动虫情测报灯的作用不可忽视。 自动虫情测报灯&#xff0c;顾名思…

腾讯云轻量服务器2核2G4M带宽118元一年,3年540「新老用户均可」

它急了&#xff0c;腾讯云急了&#xff0c;继阿里云推出99元新老用户同享的云服务器后&#xff0c;腾讯云轻量应用服务器2核2G4M配置也支持新老用户同享了&#xff0c;一年118元&#xff0c;3年540元&#xff0c;老用户也能买&#xff0c;50GB SSD系统盘&#xff0c;300GB 月流…

数据分析中常见的问题之一:怎么用SPSS来读取Stata数据文件?

我们以本书附带的“数据1F”为例进行读取Stata数据文件的讲解。“数据1F”是一个Stata数据文件&#xff0c;如图所示。 首先启动SPSS软件或者在一个已经打开的SPSS数据文件的数据视图中从菜单栏选择“文件| 打开 | 数据”命令&#xff0c;如图所示。 然后就会出现如图1.77所示的…

php安装扩展event 提示 No package ‘openssl‘ found 解决方法

在使用pecl编译安装最新版event模块的时候提示 No package openssl found , 可是本机是安装了openssl的, 编译时找不到, 大概率就是环境配置的问题了, 增加 OPENSSL_CFLAGS OPENSSL_LIBS环境变量即可解决. 异常提示信息: checking for openssl > 1.0.2... no configure: …

基于SSM的网络游戏交易平台设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;Vue 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#xff1a;是 目录…

线程的深入学习(二)

前言 上一篇讲了线程池的相关知识&#xff0c;这篇文章主要讲解一个 1.并发工具类如CountDownLatch、CyclicBarrier等。 2.线程安全和并发集合&#xff1a; 3.学习如何使用Java提供的线程安全的集合类&#xff0c;如ConcurrentHashMap、CopyOnWriteArrayList等。 并发工具类 …

2023-12-11 LeetCode每日一题(最小体力消耗路径)

2023-12-11每日一题 一、题目编号 1631. 最小体力消耗路径二、题目链接 点击跳转到题目位置 三、题目描述 你准备参加一场远足活动。给你一个二维 rows x columns 的地图 heights &#xff0c;其中 heights[row][col] 表示格子 (row, col) 的高度。一开始你在最左上角的格…

免费部署私人 ChatGPT的项目:LobeChat 14K+

前言 随着ChatGPT的快速风靡&#xff0c;所有人都对AI高度关注&#xff0c;那么你想不想部署一个属于自己的私人ChatGPT&#xff0c;用更美观&#xff0c;更高效&#xff0c;更好玩的方式来体验AI呢&#xff1f; 今天我们推荐的就是可以帮你实现在本地部署私人ChatGPT&#x…

深度学习框架解读—Yolov5/Yolov7/Halcon对比分析

作为一名机器视觉深度学习算法工程师&#xff0c;我从技术实现、性能、适用场景和易用性等方面来评价YOLOv5、YOLOv7和Halcon中的深度学习框架。以YOLOv5和YOLOv7进行比较&#xff0c;并结合Halcon的深度学习功能进行综合评价。 Yolov5 优点&#xff1a; 1. 速度快&#xff1a…

Consul

简介 Consul是一套开源的分布式服务发现和配置管理系统&#xff0c;由HashiCorp 公司用Go语言开发。 提供了微服务系统中的服务治理、配置中心、控制总线等功能。这些功能中的每一个都可以根据需要单独使用&#xff0c;也可以一起使用以构建全方位的服务网格&#xff0c;总之…

Tomcat Notes: Deployment File

This is a personal study notes of Apache Tomcat. Below are main reference material. - YouTube Apache Tomcat Full Tutorial&#xff0c;owed by Alpha Brains Courses. https://www.youtube.com/watch?vrElJIPRw5iM&t801s 1、Tomcat deployment1.1、Two modes of …

Python 热力图的绘制(Matplotlib篇-12)

Python 热力图的绘制(Matplotlib篇-12)         🍹博主 侯小啾 感谢您的支持与信赖。☀️ 🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ�…

NLP论文阅读记录 - 2021 | SimCLS:抽象概括对比学习的简单框架

文章目录 前言0、论文摘要一、Introduction1.1目标问题1.2相关的尝试1.3本文贡献 二.相关工作2.1优势 三.本文方法——抽象概括的对比学习框架3.1 第一阶段&#xff1a;候选生成3.2 第二阶段&#xff1a;无参考评估3.3对比训练 四 实验效果4.1数据集4.2 对比模型4.3实施细节4.4…

工作中redis相关知识总结

这里写目录标题 一、Redis数据持久化概念二、redis数据类型三、redis缓存的应用流程四、什么样的数据适合存放到redis中&#xff1f;1、什么情况下&#xff0c;redis中会没有数据&#xff1f;2、redis缓存项目在测试中的注意事项a、更新缓存b、淘汰缓存 五、什么是缓存击穿1、缓…
最新文章