【昕宝爸爸小模块】Java中Timer实现定时调度的原理(解析)

这篇具有很好参考价值的文章主要介绍了【昕宝爸爸小模块】Java中Timer实现定时调度的原理(解析)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

【昕宝爸爸小模块】Java中Timer实现定时调度的原理(解析),Java专栏,java,开发语言


✔️ 引言


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内存,一旦应用重启,那么队列中的任务就都没有了文章来源地址https://www.toymoban.com/news/detail-794124.html

到了这里,关于【昕宝爸爸小模块】Java中Timer实现定时调度的原理(解析)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【昕宝爸爸小模块】浅谈之创建线程的几种方式

    ➡️博客首页       https://blog.csdn.net/Java_Yangxiaoyuan        欢迎优秀的你👍点赞、🗂️收藏、加❤️关注哦。        本文章CSDN首发,欢迎转载,要注明出处哦!        先感谢优秀的你能认真的看完本文,有问题欢迎评论区交流,都会认真回复! 在Java中,共有

    2024年01月18日
    浏览(57)
  • 【昕宝爸爸小模块】日志系列之什么是分布式日志系统

    ➡️博客首页       https://blog.csdn.net/Java_Yangxiaoyuan        欢迎优秀的你👍点赞、🗂️收藏、加❤️关注哦。        本文章CSDN首发,欢迎转载,要注明出处哦!        先感谢优秀的你能认真的看完本文,有问题欢迎评论区交流,都会认真回复! 现在,很多应

    2024年02月20日
    浏览(42)
  • 【昕宝爸爸小模块】深入浅出之针对大Excel做文件读取问题

    ➡️博客首页       https://blog.csdn.net/Java_Yangxiaoyuan        欢迎优秀的你👍点赞、🗂️收藏、加❤️关注哦。        本文章CSDN首发,欢迎转载,要注明出处哦!        先感谢优秀的你能认真的看完本文,有问题欢迎评论区交流,都会认真回复! 在POI中,提供

    2024年01月18日
    浏览(44)
  • 【昕宝爸爸小模块】深入浅出之JDK21 中的虚拟线程到底是怎么回事(一)

    ➡️博客首页       https://blog.csdn.net/Java_Yangxiaoyuan        欢迎优秀的你👍点赞、🗂️收藏、加❤️关注哦。        本文章CSDN首发,欢迎转载,要注明出处哦!        先感谢优秀的你能认真的看完本文,有问题欢迎评论区交流,都会认真回复! 虚拟线程这个

    2024年01月16日
    浏览(50)
  • 【昕宝爸爸小模块】深入浅出之JDK21 中的虚拟线程到底是怎么回事(二)

    ➡️博客首页       https://blog.csdn.net/Java_Yangxiaoyuan        欢迎优秀的你👍点赞、🗂️收藏、加❤️关注哦。        本文章CSDN首发,欢迎转载,要注明出处哦!        先感谢优秀的你能认真的看完本文,有问题欢迎评论区交流,都会认真回复! 上一篇博文:

    2024年01月16日
    浏览(49)
  • 【Java|多线程与高并发】定时器(Timer)详解

    在Java中,定时器 Timer 类是用于执行定时任务的工具类。它允许你安排一个任务在未来的某个时间点执行,或者以固定的时间间隔重复执行。 在服务器开发中,客户端向服务器发送请求,然后等待服务器响应. 但服务器什么时候返回响应,并不确定. 但也不能让客户端一直等下去

    2024年02月07日
    浏览(46)
  • SpringBoot第45讲:SpringBoot定时任务 - Timer实现方式

    定时任务在实际开发中有着广泛的用途,本文是SpringBoot第45讲,主要帮助你构建定时任务的知识体系,同时展示Timer 的schedule和scheduleAtFixedRate例子;后续的文章中我们将逐一介绍其它常见的定时任务,并与SpringBoot的集成。

    2024年02月10日
    浏览(40)
  • 【Java 基础】32 定时调度

    在软件开发中,定时任务是一种常见的需求,用于周期性地执行特定的任务或操作。Java 提供了两种主要的定时调度方式: Timer 类和 ScheduledExecutorService 接口。 创建 Timer Timer 类是 Java 提供的一个简单的定时调度工具。它允许您计划一个任务在未来的某个时刻执行,也可以以固

    2024年02月05日
    浏览(27)
  • Java定时任务、自动化任务调度

    Java提供了多种方式来实现定时任务,使得开发人员能够在指定的时间间隔或固定时间点执行特定的任务。本文将介绍Java中实现定时任务的几种常用方法,并探讨它们的优势和适用场景。 Java中的Timer类是最早引入的定时任务工具,它可以用于执行一次性或重复性的定时任务。

    2024年02月16日
    浏览(52)
  • Flink timer定时器

    常见timer 基于处理时间或者事件时间处理过一个元素之后, 注册一个定时器, 然后指定的时间执行. Context和OnTimerContext 所持有的TimerService对象拥有以下方法: currentProcessingTime(): Long 返回当前处理时间 currentWatermark(): Long 返回当前watermark的时间戳 registerProcessingTimeTimer(timestamp: Lon

    2024年02月07日
    浏览(53)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包