Java定时任务

Wesley13
• 阅读 321

1.程序和编程

我们知道,计算机程序是一组计算机能识别和执行的指令,运行于电子计算机上,满足人们某种需求的信息化工具。

简单来说程序在本质上是指令的集合,而编程从字面上来讲就是编写这些指令集合(程序),通过程序去完成某种行为。

在日常编程中,我们难免会遇到这种情况,如何在指定的时间去做某一件事情(比如闹钟响铃)?在Java中通常使用定时任务去实现,接下来会结合源码分析Java中的定时任务。

2.从段子开始

Java定时任务

 上面是一个关于时间和线程的段子。当然段子毕竟是为博众人一笑,我们开发中获取时间会有更好的方式。这里要说的是,如果我们要在下一天去做某个动作(比如上面说的闹钟响铃),

这种线程睡眠不失为一种简单的方法(虽然我们通常不建议使用这种方式,更倾向使用定时任务)。

3.Java定时任务

Java定时任务

 简单的说Timer中有两个核心部分:

  • TimerThread是时间线程,控制TaskQueue中TimerTask的执行;
  • TaskQueue是一个工具类,管理TimerTask数组

而Timer暴露的主要是一系列schedule方法,去建立Timer和TimerTask的联系。我们看到Java定时任务设计中很重要的部分就是定时器和任务的分离。

Java定时任务

以上是简单的示例,在使用定时任务时要注意几点:

  • 一个Timer可以执行多个TimerTask,但一个TimerTask只能被一个Timer使用(这和schedule中校验TimerTask的状态有关,TimerTask的生命周期(由不同的状态确定))。
  • 通常不使用匿名类创建TimerTask抽象类的子类,建议创建单独的子类extend TimerTask。
  • 根据实际需要采用不同的schedule方法或者scheduleAtFixedRate方法执行任务。
  • 合理使用cancel和purge方法。

4.源码浅析

结合第3部分的简单示例,来梳理源码。

①创建Timer和TimerTask

Timer的核心构造方法,调用此方法时启动,初始化创建的TimerThread线程。

Java定时任务 Java定时任务

②执行schedule或scheduleAtFixedRate方法

Java定时任务

 其中核心的sched方法,主要是判断线程的状态,TimerTask的状态,然后将通过校验的TimerTask添加到TaskQueue,其后交由TimerThread管理。

③TimerThread原理

Java定时任务Java定时任务

时间线程TimerThread中run方法执行的mianLoop方法如上,会一直循环执行。

a.获取TaskQueue中的第一个序列的TimerTask(通过getMin()方法获取),这里很重要,每次循环后TaskQueue序列可能会变化。

b.然后校验TimerTask的状态,移除TaskQueue不需要执行的TimerTask

c.对于能够执行的TimerTask,校验当前时间和执行时间, 通过taskFired标识(表示TimerTask是否就绪,可以执行),(然后处理只执行一次的,从TaskQueue中移除,按频率执行多次的重新排序,详见rescheduleMin方法)。

d.未就绪的TimerTask将wait,而就绪(状态正常且到执行时间的TimerTask)的执行TimerTask的run方法。此时该Timer中的TimerTask执行完毕,后续的就是TimerTask线程逻辑。

④TaskQueue和TimerTask

结合源码可以了解TaskQueue如何排序,以及TimerTask中不同的状态(生命周期)的意义。

4.总结

Java原生的定时任务包括Timer和TimerTask两部分,Timer为主,TimerTask为辅。

Timer中由TimerThread线程控制TimerTask是否执行,Java通过这两个类完成了定时任务的基本功能。

学习时不只是要学习其源码中内部实现,工作原理。更要关注Timer和TimerTask分离的思想,这很重要。

后续学习Java中其他的定时任务,如Spring的定时任务,Quartz。

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Wesley13 Wesley13
2年前
Java日期时间API系列31
  时间戳是指格林威治时间1970年01月01日00时00分00秒起至现在的总毫秒数,是所有时间的基础,其他时间可以通过时间戳转换得到。Java中本来已经有相关获取时间戳的方法,Java8后增加新的类Instant等专用于处理时间戳问题。 1获取时间戳的方法和性能对比1.1获取时间戳方法Java8以前
Stella981 Stella981
2年前
Android So动态加载 优雅实现与原理分析
背景:漫品Android客户端集成适配转换功能(基于目标识别(So库35M)和人脸识别库(5M)),导致apk体积50M左右,为优化客户端体验,决定实现So文件动态加载.!(https://oscimg.oschina.net/oscnet/00d1ff90e4b34869664fef59e3ec3fdd20b.png)点击上方“蓝字”关注我
Easter79 Easter79
2年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Stella981 Stella981
2年前
HIVE 时间操作函数
日期函数UNIX时间戳转日期函数: from\_unixtime语法:   from\_unixtime(bigint unixtime\, string format\)返回值: string说明: 转化UNIX时间戳(从19700101 00:00:00 UTC到指定时间的秒数)到当前时区的时间格式举例:hive   selec
Wesley13 Wesley13
2年前
35岁,真的是程序员的一道坎吗?
“程序员35岁是道坎”,“程序员35岁被裁”……这些话咱们可能都听腻了,但每当触及还是会感到丝丝焦虑,毕竟每个人都会到35岁。而国内互联网环境确实对35岁以上的程序员不太友好:薪资要得高,却不如年轻人加班猛;虽说经验丰富,但大部分公司并不需要太资深的程序员。但35岁危机并不是不可避免的,比如你可以不断精进技术,将来做技术管理或者
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
京东云开发者 京东云开发者
7个月前
Java服务总在半夜挂,背后的真相竟然是... | 京东云技术团队
最近有用户反馈测试环境Java服务总在凌晨00:00左右挂掉,用户反馈Java服务没有定时任务,也没有流量突增的情况,Jvm配置也合理,莫名其妙就挂了