Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >JDK Timer 实现原理分析

JDK Timer 实现原理分析

作者头像
Yano_nankai
发布于 2018-10-08 02:31:19
发布于 2018-10-08 02:31:19
48200
代码可运行
举报
文章被收录于专栏:二进制文集二进制文集
运行总次数:0
代码可运行

说明

本文分析的是 JDK 7

Timer 基本用法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public static void main(String[] args) {
    Timer timer = new Timer();
    timer.scheduleAtFixedRate(new TimerTask() {
        
        @Override
        public void run() {
            System.out.println(new Date(this.scheduledExecutionTime()));
        }
        
    }, 500L, 1000L);
}

输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Mon Jul 02 14:34:20 CST 2018
Mon Jul 02 14:34:21 CST 2018
Mon Jul 02 14:34:22 CST 2018
Mon Jul 02 14:34:23 CST 2018
Mon Jul 02 14:34:24 CST 2018
Mon Jul 02 14:34:25 CST 2018

主要能够指定定时任务的初始延迟、间隔执行时间。

实现原理

首先画了一张示意图,能够说明 Timer 的基本原理。

大体上有 4 个类:

  • Timer:定时器主类
  • TimerTask:实现了 Runnable 的抽象类(run 仍为抽象方法,需要用户实现),定义了与 Timer 特有的任务状态(下一次执行时间 nextExecutionTime 和 执行时间间隔 period)
  • TimerThread:由 Timer 启动,里面有个无限循环的 mainLoop 方法,用来取出 TaskQueue 中最近需要执行的任务,判断是否需要执行。
  • TaskQueue:由 TimerTask 组成的小顶堆,其排序是根据 TimerTask 的 nextExecutionTime。

TimerTask 的状态

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * The state of this task, chosen from the constants below.
 */
int state = VIRGIN;

/**
 * This task has not yet been scheduled.
 */
static final int VIRGIN = 0;

/**
 * This task is scheduled for execution.  If it is a non-repeating task,
 * it has not yet been executed.
 */
static final int SCHEDULED   = 1;

/**
 * This non-repeating task has already executed (or is currently
 * executing) and has not been cancelled.
 */
static final int EXECUTED    = 2;

/**
 * This task has been cancelled (with a call to TimerTask.cancel).
 */
static final int CANCELLED   = 3;

Timer 的两个方法

  • schedule
  • scheduleAtFixedRate

函数的定义如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public void schedule(TimerTask task, long delay, long period) {
    if (delay < 0)
        throw new IllegalArgumentException("Negative delay.");
    if (period <= 0)
        throw new IllegalArgumentException("Non-positive period.");
    sched(task, System.currentTimeMillis()+delay, -period);
}

public void scheduleAtFixedRate(TimerTask task, long delay, long period) {
    if (delay < 0)
        throw new IllegalArgumentException("Negative delay.");
    if (period <= 0)
        throw new IllegalArgumentException("Non-positive period.");
    sched(task, System.currentTimeMillis()+delay, period);
}

注意其中最大的区别,在于 schedule 调用 sched 函数时,将传入的 period 取反了。如果某次执行任务的开始时间延后了,那么此后的每次任务都会延迟。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
If an execution is delayed for any reason (such as garbage collection or other background activity), subsequent executions will be delayed as well. In the long run, the frequency of execution will generally be slightly lower than the reciprocal of the specified period (assuming the system clock underlying Object.wait(long) is accurate). As a consequence of the above, if the scheduled first time is in the past, it is scheduled for immediate execution. 

而 scheduleAtFixedRate 则并不会这样。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
If an execution is delayed for any reason (such as garbage collection or other background activity), two or more executions will occur in rapid succession to "catch up." In the long run, the frequency of execution will be exactly the reciprocal of the specified period (assuming the system clock underlying Object.wait(long) is accurate). 

其加入后的核心函数是 sched。参数 period

  • 0:重复任务的时间间隔(scheduleAtFixedRate)
  • =0:仅执行一次
  • <0:重复任务的时间间隔(schedule)
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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();
    }
}

TimerTask 核心方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * The main timer loop.  (See class comment.)
 */
private void mainLoop() {
    while (true) {
        try {
            TimerTask task;
            boolean taskFired;
            synchronized(queue) {
                // Wait for queue to become non-empty
                while (queue.isEmpty() && newTasksMayBeScheduled)
                    queue.wait();
                if (queue.isEmpty())
                    break; // Queue is empty and will forever remain; die

                // Queue nonempty; look at first evt and do the right thing
                long currentTime, executionTime;
                task = queue.getMin();
                synchronized(task.lock) {
                    if (task.state == TimerTask.CANCELLED) {
                        queue.removeMin();
                        continue;  // No action required, poll queue again
                    }
                    currentTime = System.currentTimeMillis();
                    executionTime = task.nextExecutionTime;
                    if (taskFired = (executionTime<=currentTime)) {
                        if (task.period == 0) { // Non-repeating, remove
                            queue.removeMin();
                            task.state = TimerTask.EXECUTED;
                        } else { // Repeating task, reschedule
                            queue.rescheduleMin(
                              task.period<0 ? currentTime   - task.period
                                            : executionTime + task.period);
                        }
                    }
                }
                if (!taskFired) // Task hasn't yet fired; wait
                    queue.wait(executionTime - currentTime);
            }
            if (taskFired)  // Task fired; run it, holding no locks
                task.run();
        } catch(InterruptedException e) {
        }
    }
}

整体流程是:获取 queue 的锁,若 queue 不为空,则拿出第一个任务,获取任务的锁,若任务的状态正常且到执行时间,则执行任务;否则将其 wait 对应的时间。

其最核心的代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
currentTime = System.currentTimeMillis();
executionTime = task.nextExecutionTime;
if (taskFired = (executionTime<=currentTime)) {
    if (task.period == 0) { // Non-repeating, remove
        queue.removeMin();
        task.state = TimerTask.EXECUTED;
    } else { // Repeating task, reschedule
        queue.rescheduleMin(
          task.period<0 ? currentTime   - task.period
                        : executionTime + task.period);
    }
}

费曼技巧:概述 Timer 的实现原理

Timer 是 JDK 自带的执行定时任务的工具类,用户能够指定延迟、任务执行的时间间隔。当 new 一个 Timer 时,会自动启动一个 TimerTask 线程,这个线程无限循环一个小顶堆的任务队列,每次取出最近需要执行的任务,如果符合条件则对该任务(小顶堆)做相应处理。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018.07.02 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
java定时器之Timer使用与原理分析[通俗易懂]
Timer是jdk中提供的一个定时器工具,使用的时候会在主线程之外起一个单独的线程执行指定的计划任务,可以指定执行一次或者反复执行多次。
全栈程序员站长
2022/09/08
7560
Java Timer定时器原理
做项目很多时候会用到定时任务,比如在深夜,流量较小的时候,做一些统计工作。早上定时发送邮件,更新数据库等。这里可以用Java的Timer或线程池实现。Timer可以实现,不过Timer存在一些问题。他起一个单线程,如果有异常产生,线程将退出,整个定时任务就失败。
技术从心
2019/08/06
1.4K0
TimerTask(addin timer语音)
其实就Timer来讲就是一个调度器,而TimerTask呢只是一个实现了run方法的一个类,而具体的TimerTask需要由你自己来实现,例如这样:
全栈程序员站长
2022/08/02
6180
定时器的实现原理及参考
如果让你来实现一个定时器的功能,简单点就是,每隔n秒,去执行一次A任务,你打算怎么实现
烂猪皮
2022/05/17
4620
面试必问!JDK 中定时器是如何实现的?
Demo中使用了Timer实现了一个定时任务,该任务在每天12点开始执行,并且每隔2秒执行一次。
Java小咖秀
2021/04/20
4100
看 JDK 源码,解几个疑问
解包 jdk_sec-1_5_0-src-jrl,在/j2se/src/share/classes/java/util 中找到 Timer 类。
四火
2022/07/15
1580
看 JDK 源码,解几个疑问
定时任务的实现原理,看完就能手撸一个!
在很多业务的系统中,我们常常需要定时的执行一些任务,例如定时发短信、定时变更数据、定时发起促销活动等等。
macrozheng
2021/01/06
4.5K0
定时任务的实现原理,看完就能手撸一个!
深入 Java Timer 定时任务调度器实现原理
使用 Java 来调度定时任务时,我们经常会使用 Timer 类搞定。Timer 简单易用,其源码阅读起来也非常清晰,本节我们来仔细分析一下 Timer 类,来看看 JDK 源码的编写者是如何实现一个稳定可靠的简单调度器。
老钱
2018/12/27
1.2K0
线上服务启动卡死,堆栈分析
这一步,就是等待队列为非空的时候,才会执行下去,但是现在队列一直为空,线程都在等待。
MickyInvQ
2020/09/27
2.3K0
线上服务启动卡死,堆栈分析
Java 定时任务实现原理详解[通俗易懂]
在jdk自带的库中,有两种技术可以实现定时任务。一种是使用Timer,另外一个则是ScheduledThreadPoolExecutor。下面为大家分析一下这两个技术的底层实现原理以及各自的优缺点。
全栈程序员站长
2022/07/25
8960
【Android 异步操作】Timer 定时器 ( Timer 与 TimerTask 基本使用 | Timer 定时器常用用法 | Timer 源码分析 )
2 . 定时器任务执行规则 : Timer 执行任务是 串行执行 的 , 同一时间只能执行一个任务 ;
韩曙亮
2023/03/28
3.5K0
JDK中的timer正确的打开与关闭
Timer是jdk中提供的一个定时器工具,使用的时候会在主线程之外起一个单独的线程执行指定的计划任务,可以指定执行一次或者反复执行多次。
一觉睡到小时候
2020/05/27
1.8K0
定时器算法
在日常开发中, 定时任务是一个比较关键的功能。 Java 中一般使用 JDK 中 Timer、ScheduledExecutorService 和调度框架 Quartz等。 通常用于实现延时任务, 周期性任务等, 一般会有两种需求:
leobhao
2022/06/28
9680
定时器算法
手把手教你写一个延时队列
这种实现方式下多个定时任务需要开启多个线程,而且线程在做无意义sleep,消耗资源,性能低下。
派大星在吗
2021/12/18
5040
实现线程的方式到底有几种?
这篇文章主要讲解实现线程的方式到底有几种?以及实现 Runnable 接口究竟比继承 Thread 类实现线程好在哪里?
武培轩
2020/02/16
1.9K0
Java基础知识扫盲
Arrays.sort是Java中提供的对数组进行排序的方法,根据参数类型不同,它提供了很多重载方法:
ma布
2024/10/21
550
Java基础知识扫盲
微信和QQ这么多群,该如何管理好友关系?
在现实生活中,中介者的存在是不可缺少的,如果没有了中介者,我们就不能与远方的朋友进行交流。各个同事对象将会相互进行引用,如果每个对象都与多个对象进行交互,则会形成如下图所示的网状结构。
Tom弹架构
2021/12/21
6400
微信和QQ这么多群,该如何管理好友关系?
微信和QQ这么多群,该如何管理好友关系?
在现实生活中,中介者的存在是不可缺少的,如果没有了中介者,我们就不能与远方的朋友进行交流。各个同事对象将会相互进行引用,如果每个对象都与多个对象进行交互,则会形成如下图所示的网状结构。
Tom弹架构
2021/11/24
5800
设计模式 | 行为型 | 中介者模式
该模式会限制对象之间的直接交互,迫使它们通过一个中介者对象进行合作(中转与协调)。
被水淹没
2023/02/25
2080
设计模式 | 行为型 | 中介者模式
048android初级篇之定时器Timer和TimerTask的详细使用
Timer是jdk中提供的一个定时器工具,使用的时候会在主线程之外起一个单独的线程执行指定的计划任务,可以指定执行一次或者反复执行多次。
上善若水.夏
2018/09/28
1.7K0
推荐阅读
相关推荐
java定时器之Timer使用与原理分析[通俗易懂]
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档