【tomcat 源码构建】【app开发源码网站源码】【网站源码交易网源码】timertask 源码

时间:2024-12-28 09:36:33 来源:ckeditor 源码模式 分类:探索

1.【JDK源码分析】Timer/TimerTask 源码分析
2.Java中Timer类的schedule方法开始计时时间是不是创建timer对象的时刻
3.Kafka源码分析(五) - Server端 - 基于时间轮的延时组件
4.Timer & TimerTask 源码分析
5.java怎么每隔一秒钟输出一个随机数(1-10之间)

timertask 源码

【JDK源码分析】Timer/TimerTask 源码分析

       在Java中,Timer 类是实现定时任务的常见工具,配合TimerTask 实现定时、延迟或周期性执行。本文将深入剖析其源码结构和工作原理。

       Timer 的tomcat 源码构建核心机制涉及关键类,包括TimerThread、Timer、TimerQueue 和 TimerTask。一个Timer 实例对应一个TimerThread,负责执行任务;Timer拥有一个TimerThread和一个TimerQueue,而TimerQueue中存储了多个TimerTask。这样的关系可以总结为:

       1个 TimerThread -> 1个线程

       1个 Timer -> 持有 TimerThread 和 TimerQueue

       1个 TimerQueue -> 持有多个 TimerTask

       源码分析时,首先创建Timer时,thread和queue会在声明时初始化为final类型,app开发源码网站源码确保它们与Timer的生命周期绑定。接着,任务通过schedule方法进行调度,这个过程会根据TimerTask类型设置不同的period参数。

       TimerTask 是一个实现了Runnable接口的抽象类,子类需实现run方法。TimerTask的类型决定了其执行周期。TimerThread的run方法包含一个死循环,类似Android的Handler机制。

       TimerQueue作为队列,内部使用完全二叉树结构,add和fixUp方法用于维护最小执行时间的节点在队列前端。purge方法执行后,会调用fixDown方法进行调整。网站源码交易网源码

       总之,每个Timer实例由一个线程和一个二叉堆(通过TimerQueue实现)组成,用于管理定时任务的执行顺序。理解这些核心组件的交互,有助于深入理解Timer的工作机制。

Java中Timer类的schedule方法开始计时时间是不是创建timer对象的时刻

       通过查看JDK源码可以知道如下:

        public void schedule(TimerTask task, long delay) {

        if (delay < 0)

        throw new IllegalArgumentException("Negative delay.");

        sched(task, System.currentTimeMillis()+delay, 0);

        }

       实际上调用的是如下方法:

        private void sched(TimerTask task, long time, long period)

       //task:安排的任务,the scheduled task;

       //time:指定的时间去执行

        * at the specified time with the specified period, in milliseconds.

       //period:如果period是正数,则会重复执行任务,如果是零则只执行任务一次

        If period is

        * positive, the task is scheduled for repeated execution;

        * zero, the task is scheduled for one-time execution.

       因此可以分析到 中间书写的语句不会算在延迟时间中,程序的开始时刻就是执行到timer.schedule(new Task(),);//语句时,开始计时。而Timer timer = new Timer() 只是创建了一个Timer类对象。

       只有程序执行到timer.schedule(new Task(),)时,才会调用

       sched(task, System.currentTimeMillis()+delay, 0)方法,而这时该方法

       才去执行System.currentTimeMillis取得当前时间,宗亲网站宗亲网站源码源码并将该任务加到TaskQueue队列中

       (自带任务队列),经过System.currentTimeMillis+毫秒后根据指定状态执行指定任务.

Kafka源码分析(五) - Server端 - 基于时间轮的延时组件

       Kafka内部处理大量的延时操作,例如,在接收到PRODUCE请求后,副本可以等待一个timeout的时间再响应客户端。下面我们来探讨一个问题:为什么Kafka要自己实现一个延时任务组件,而不是直接使用Java的java.util.concurrent.DelayQueue呢?我们可以从以下两个方面来分析这个问题。

       1.1 DelayQueue的能力

       DelayQueue相关的接口/类如下所示:

       相应地,DelayQueue提供的能力如下:

       1.2 Kafka的业务场景

       Kafka的业务背景具有以下特点:

       相应地,Kafka对延时任务组件有以下两点要求:

       这两点要求都无法通过直接应用DelayQueue的方式得到满足。

       二. 组件接口

       让我们来看看Kafka的延时任务组件对外提供的接口,从而了解其提供的能力和使用方式。

       如下所示:

       左边的两个类定义了"延时操作",右边的DelayedOperationPurgatory类定义了一个维护DelayOperaton的容器,其核心操作如下:

       三. 实现

       以下是正数的源码负数的源码关于"延时"实现方式的介绍。

       3.1 业务模型

       时间轮延时组件的思路如下:

       接下来,通过一个具体的例子来说明这种映射逻辑:

       首先关注上图中①号时间轮。圆环中的每一个单元格表示一个TimerTaskList。单元格有其关联的时间跨度;下方的"1s x "表示时间轮上共有个单元格,每个单元格的时间跨度为1秒。有一个指针指向了"当前时间"所对应的单元格。顺时针方向为时间流动方向。

       当收到一个延迟时间在0-1s的TimerTask时,会将其追加到①号时间轮的橙色单元格中。当收到一个延迟时间在3-4s的TimerTask时,会将其追加到①号时间轮的**单元格中。以此类推。

       现在有一个问题:①号时间轮能表示的最大延迟时间是秒,那如果收到了延迟秒的任务该怎么办?这时该用到②号时间轮了,我们称②号为①号的"溢出时间轮"。②号时间轮的特点如下:

       如此,延迟时间在-s的TimerTask会被追加到②号的紫色单元格,延迟时间在-s的TimerTask会被追加到②号的绿色单元格中。③号时间轮同理。

       刚刚是按①->②->③的顺序来分析时间轮的逻辑,反过来也可以得到有用的想象手里有一个"放大镜",其实③号时间轮的蓝色单元格"放大"后是②号时间轮;②号时间轮的蓝色单元格"放大"后是①号时间轮;蓝色单元格并不实际存储TimerTask。

       3.2 数据结构

       DelayedOperationPurgatory有一个Timer类型的timeoutTimer属性,用于维护延时任务。实际使用的是Timer的实现类:SystemTimer。该类用于维护延时任务的核心属性有两个:delayQueue和timingWheel。TimingWheel表示单个时间轮,接下来我们来看看其类图:

       各属性含义如下:

       3.3 算法

       3.3.1 添加任务

       添加任务的入口是DelayedOperationPurgatory.tryCompleteElseWatch,其核心逻辑分为如下两步:

       SystemTimer.add直接调用了addTimerTaskEntry方法,后者逻辑如下:

       TimingWheel.add的逻辑也很清晰,分如下4种场景处理:

       3.3.2 尝试提前触发任务

       入口是DelayedOperationPurgatory.checkAndComplete:

       接下来看Watchers.tryCompleteWatched方法的内容:

       DelayedOperation.maybeTryComplete方法最终调用了DelayedOperation.tryComplete;

       DelayedOperation的子类需要在后者中实现自己的"触发条件"检查逻辑;若满足了提前触发的条件,则调用forceComplete方法执行事件触发场景下的业务逻辑。

       3.3.3 任务到期自动执行

       DelayedOperationPurgatory中维护了一个expirationReaper线程,其职责就是循环调用kafka.utils.timer.SystemTimer#advanceClock来从时间轮中获取已超时的任务,并更新时间轮的"当前时间"指针。

       四. 总结

       才疏学浅,未能窥其十之一二,随时欢迎各位交流补充。若文章质量还算及格,可以点赞收藏加以鼓励,后续我继续更新。

       另外,也可以在目录中找到同系列的其他文章:

       感谢阅读。

Timer & TimerTask 源码分析

       尽管 Timer 已经在现代 Java 开发中鲜少使用,但其内部结构对理解和实现自动化流程有着重要参考价值。这篇源码分析着重于 Timer 和 TimerTask 的工作原理,它们通过维护一个 TaskQueue,确保任务按照预设时间执行,其中的并发处理策略对初学者极具启发性。

       在 Timer 类中,每个 Timer 实例对应一个单独的线程,这可能导致任务执行顺序受阻。Timer 的生命周期不确定,任务完成后可能不会立即回收,而 ScheduledThreadPoolExecutor 是推荐的替代方案。Timer 是线程安全的,但不保证任务执行的实时性,而是依赖于 wait() 等待机制。TaskQueue 是 TimerThread 的核心,它负责调度任务的执行。

       TimerThread 是负责执行任务的线程,继承自 Thread,其简洁的实现表明了其功能的专注。Timer 的构造器和 schedule 方法提供多种重载形式,而 sched 方法是它们的最终调用者。TimerTask 是一个抽象类,实现了 Runnable,用户需创建其子类并覆盖 run 方法,定义了任务的状态标识和执行时间属性。

       尽管 Timer 已经过时,但理解其内部机制有助于在需要定时任务的场景中找到更高效、可靠的解决方案。

java怎么每隔一秒钟输出一个随机数(1-之间)

       可以用 java.util.Timer(计时器) 以及 java.util.TimerTask(计时任务) 来实现,具体代码如下:

import java.io.IOException;

       import java.util.Random;

       import java.util.Timer;

       import java.util.TimerTask;

       public class Main {

           public static void main(String[] args) throws IOException, InterruptedException {

               // 创建一个计时器

               Timer timer = new Timer();

               // 开启一个计时调度,延迟 0毫秒(也就是立即开始执行),调度评率: 1秒

               timer.schedule(new TimerTask() {

                   @Override

                   public void run() {

                       // 生成随机数逻辑

                       Random r = new Random();

                       int num = r.nextInt() + 1;

                       System.out.println("随机数为:" + num);

                   }

               }, 0L, L);

               // timer.cancel();  // 关闭计时器

           }

       }