Timer 定时器

为什么要使用定时器呢?

  • 比如说一个web应用,如果这个应用规模很大,那它的日志数据是不是很多。如果一直存下来服务器的存储量怕是不行吧,需要隔一段时间删除,那么就需要一个线程每隔一段时间去删除日志数据。

概念:Java java.util.Timer

Java java.util.Timer是一种定时器工具,用来在一个后台线程计划执行指定任务。它可以计划执行一个任务一次或反复多次.

概念:Java TimerTask

1.TimerTask一个抽象类,它的子类代表一个可以被Timer计划的任务。具体的任务在TimerTask中run接口中实现。通过Timer中的schedule方法启动定时任务。

Timer timer = new Timer();
timer.schedule(new TimerTask() {public void run() {System.out.println("11232");}
}, 200000 , 1000);

Timer 类讲解

Timer.java中含有3个类:Timer、TimerThread、TaskQueue。

TaskQueue

  • TaskQueue中存放一些列将要执行的TimerTask,以数组的形式存放,下标约小(注:下标为0不处理,即使用的最小下标为1),则表明优先级越高。

TimerThread

  • TimerThread继承Thread类,会一直从TaskQueue中获取下标为1的TimerTask进行执行。并根据该TimerTask是否需要重复执行来决定是否放回到TaskQueue中。

Timer

  • Timer用于配置用户期望的任务执行时间、执行次数、执行内容。它内部会配置,调度TimerThread、TaskQueue。

Timer 构造方法:

  1. Timer timer = new Timer(); //其中会调用this(“Timer-” + serialNumber());, 即它以Timer+序列号为该定时器的名字
  2. Timer timer = new Timer(String name); //以name作为该定时器的名字
  3. Timer timer = new Timer(boolean isDeamon); //是否将此定时器作为守护线程执行
  4. Timer timer = new Timer(name, isDeamon); //定时器名字, 是否为守护线程

创建一个 Timer 对象就是新启动了一个线程,但是这个新启动的线程,并不是守护线程,它一直在后台运行.

运行定时器

  1. 启动一个定时器实质是启动一个线程
  2. 所有的task都是TimerTask的子类
  3. 所有time都是Date类型的日期
  4. 所有delay和period都是long类型的延迟时间, 单位为毫秒

API:

schedule

  • timer.schedule(task, time);
    在time时间执行task任务1次

  • timer.schedule(task, delay);
    在延迟delay毫秒后执行task任务1次

  • timer.schedule(task, firstTime, period);
    在firsttime时间执行task1次,之后定期period毫秒时间执行task, 时间如果为过去时间,不会执行过去没有执行的任务, 但是会马上执行

  • timer.schedule(task, delay, period);
    在延迟delay后执行task1次,之后定期period毫秒时间执行task, 时间如果为过去时间, 不会执行过去没有执行的任务, 但是会马上执行

scheduleAtFixedRate

  • timer.scheduleAtFixedRate(task, firstTime, period);
    在firstTime时间执行task一次, 以后每隔period毫秒执行1次, 时间如果为过去时间, 会执行过去没有执行的任务, 但是会马上执行
  • timer.scheduleAtFixedRate(task, delay, period);
    在delay毫秒后执行task一次, 以后每隔period毫秒执行1次, 时间如果为过去时间, 会执行过去没有执行的任务, 但是会马上执行

启动任务schedule 与 scheduleAtFixedRate的区别

  • 方法schedule 和方法 scheduleAtFixedRate 在使用上基本没什么差别,就是 scheduleAtFixedRate 具有追赶执行性,
  • 什么意思呢?就是如果任务 在周期性运行过程中被打断了,scheduleAtFixedRate会尝试把之前落下的任务补上运行。而schedule就不管了,接着运行接下来的任务就行了.

1、在指定日期运行定时器任务,只运行一次

如果date日期在今天之前,则启动定时器后,立即运行一次定时任务run方法

如果date日期在今天之后,则启动定时器后,会在指定的将来日期运行一次任务run方法

    public static void main(String[] args) throws  ParseException {String sdate = "2018-02-14";SimpleDateFormat sf = new SimpleDateFormat("yy-MM-dd");Date date = sf.parse(sdate);Timer timer = new Timer();timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("系统正在运行……");}}, date); //在指定的日期运行一次定时任务/*如果date日期在今天之前,则启动定时器后,立即运行一次定时任务run方法*//*如果date日期在今天之后,则启动定时器后,会在指定的将来日期运行一次任务run方法*/}

2、在距当前时刻的一段时间后运行定时器任务,只运行一次

指定启动定时器5s之后运行定时器任务run方法,并且只运行一次

  public static void main(String[] args) throws  ParseException {Timer timer = new Timer();timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("系统正在运行……");}}, 5000); //指定启动定时器5s之后运行定时器任务run方法,并且只运行一次}

3、在指定的时间后,每隔指定的时间,重复运行定时器任务

如果指定的date时间是当天或者今天之前,启动定时器后会立即每隔2s运行一次定时器任务

如果指定的date时间是未来的某天,启动定时器后会在未来的那天开始,每隔2s执行一次定时器任务

public static void main(String[] args) throws  ParseException {String sdate = "2018-02-10";SimpleDateFormat sf = new SimpleDateFormat("yy-MM-dd");Date date = sf.parse(sdate);Timer timer = new Timer();timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("系统正在运行……");}}, date, 2000);/*如果指定的date时间是当天或者今天之前,启动定时器后会立即每隔2s运行一次定时器任务*//*如果指定的date时间是未来的某天,启动定时器后会在未来的那天开始,每隔2s执行一次定时器任务*/}

4、在距当前时刻的一段指定距离后,每隔指定时间运行一次定时器任务

当启动定时器后,5s之后开始每隔2s执行一次定时器任务

 public static void main(String[] args) throws  ParseException {Timer timer = new Timer();timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("系统正在运行……");}}, 5000, 2000);/*当启动定时器后,5s之后开始每隔2s执行一次定时器任务*/}

停止定时器

停止定时器实质是终止Timer的线程。默认情况下,创建的Timer线程会一直执行,如果要停止的话主要有以下四种方法终止Timer线程:

  1. 调用Timer的cancel方法;
  2. 把Timer线程设置成Daemon守护线程,当所有的用户线程结束后,那么守护线程也会被终止;
  3. 当所有的任务执行结束后,删除对应Timer对象的引用,线程也会被终止;
  4. 调用System.exit方法终止程序

举例用cancel方法终止Timer线程

    public static void main(String[] args) throws InterruptedException {Timer timer = new Timer();timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("系统正在运行……");
//              timer.cancel(); //可以在任何时刻调用cancel方法终止timer线程}}, 5000, 2000);/*如果主线程不休眠一段时间,就执行了cancel方法,那么定时器还没来得及执行就会被关闭*/Thread.sleep(6000);timer.cancel();}

举例让timer线程成为一个daemon守护线程

  • 可以在创建timer时使用new Timer(true)达到这个目地,这样当程序只有daemon线程的时候,它就会自动终止运行。
  public static void main(String[] args) throws  ParseException {Timer timer = new Timer(true);timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("系统正在运行……");}}, 5000, 2000);/*当启动定时器后,5s之后开始每隔2s执行一次定时器任务*/}

一些注意的问题

  • 每一个Timer仅对应唯一一个线程。
  • Timer不保证任务执行的十分精确。
  • Timer类的线程安全的。

sched方法:

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) {//判断Timer是否已经取消if (!thread.newTasksMayBeScheduled)throw new IllegalStateException("Timer already cancelled.");synchronized(task.lock) {//TimerTask.VIRGIN标记任务没有被调度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)//将TimerTask放到队列中,并进行队列排序queue.notify();//如果队列里恰好下标为1的任务为当前的task,则直接唤醒//注意最小的值是从下标为1的获取,queue[0]其实没用到}
}
  • 数据已经放到queue中了,那么看下是什么时候执行的。在之前Timer的构造函数这块,有一句是:thread.start();说明TimerThread在Timer初始化之后就一直启用着,那看下它的处理。

TimerThread的run() 方法:

 public void run() {try {mainLoop(); //主要实现内容} finally {// Someone killed this Thread, behave as if Timer cancelledsynchronized(queue) {newTasksMayBeScheduled = false;queue.clear();  // Eliminate obsolete references}}}/*** 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//如果队列为空并且是有标志位,则等待。没有标志位的情况为不在需要执行timer了,比如cancel或被gc的时候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 thinglong currentTime, executionTime;//分别是当前时间、理论执行时间task = queue.getMin();//获取就近的tasksynchronized(task.lock) {//如果该task已经被置为cancelled,则将它从队列里面移出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) { // period表示该task是一次性的,用完就移出queue.removeMin();//移出task,这块会有queue的重新排序task.state = TimerTask.EXECUTED;//更新状态为执行中} else {//可重复执行的task操作,将重新计算下次执行时间,并重新排序    //重点,此处解释为什么period分正负:区别schedule方法和scheduleAtFixedRate//如果是负数,则以当前时间为准,往后计算下次执行时间//如果是正数,则以理论时间为准,往后计算下次执行时间queue.rescheduleMin(task.period<0 ? currentTime   - task.period: executionTime + task.period);}}}if (!taskFired) // 如果还没到任务执行时间就处于等待queue.wait(executionTime - currentTime);}if (taskFired)  // 到执行时间了//执行task中的run方法,而不是start方法,所以并不是另起一个线程进行操作task.run();} catch(InterruptedException e) {//如果是不能捕获的异常,就会有风险了}}}

java--Timer 定时器相关推荐

  1. JAVA Timer 定时器

    JAVA  Timer 定时器测试 MyTask.java: package com.timer; import java.text.SimpleDateFormat; import java.uti ...

  2. java Timer定时器管理类

    1.java timer类,定时器类.启动执行定时任务方法是timer.schedule(new RemindTask(), seconds*1000);俩参数分别是TimerTask子类,具体执行定 ...

  3. Java Timer定时器 使用

    2019独角兽企业重金招聘Python工程师标准>>> Java 自带的定时器,有两个重要的类:TimerTask和Timer. 如下: 简单的使用: package com;imp ...

  4. Java Timer 定时器的使用

    一.延时执行首先,我们定义一个类,给它取个名字叫TimeTask,我们的定时任务,就在这个类的main函数里执行. 代码如下: package test; import java.util.Timer ...

  5. java timer指定线程池_Java 定时器(Timer)及线程池里使用定时器实例代码

    java Timer定时器 简单实例代码:public class Test { public static void main(String[] args) { // Timer定时器 Timer ...

  6. java之定时器任务Timer用法

    在项目开发中,经常会遇到需要实现一些定时操作的任务,写过很多遍了,然而每次写的时候,总是会对一些细节有所遗忘,后来想想可能是没有总结的缘故,所以今天小编就打算总结一下可能会被遗忘的小点: 1. pub ...

  7. java项目中多个定时器_在java项目中如何使用Timer定时器

    在java项目中如何使用Timer定时器 发布时间:2020-11-16 16:36:16 来源:亿速云 阅读:97 作者:Leah 在java项目中如何使用Timer定时器?很多新手对此不是很清楚, ...

  8. java timer线程结束_Java线程Timer定时器用法详细总结

    定时/计划功能主要使用的就是Timer对象,它在内部还是使用多线程的方式进行处理,所以它和线程技术还是有非常大的关联. Timer类主要作用就是设置计划任务,但封装任务的类却是TimerTask类.T ...

  9. Java的定时器Timer和定时任务TimerTask应用以及原理简析

    记录:272 场景:Java JDK自带的定时器Timer和定时任务TimerTask应用以及原理简析.在JDK工具包:java.util中可以找到源码,即java.util.Timer和java.u ...

  10. Java 中Timer定时器设置订单提交后24小时未付款订单状态为已关闭。

    1. 简单的Timer定时器方法 public class CommTimer {/*** 设置指定24小时后执行*/public static void orderClose() {final Ti ...

最新文章

  1. java 反射 慢在那里_Java 反射到底慢在哪?
  2. XamarinEssentials教程移除键值首选项的键值
  3. openssl生成rsa密钥对和密钥格式转换
  4. 生产问题:一个线程罢工的诡异事件
  5. Zabbix 3.2.6通过SNMP和iDRAC监控DELL服务器
  6. Java的四种引用,强弱软虚,用到的场景(转+补充)
  7. python如何读二进制文件_python怎么读二进制文件
  8. C++ 类的知识 | 构造函数再探、匿名对象、友元函数、内部类、类的const成员、类的static成员
  9. Python机器学习:PCA与梯度上升001什么是PCA
  10. 产业区块链:新基建中的底层技术基座,各行业资深人士应积极参与建设
  11. 阶乘浅析poj1150 3406 zoj1222 2358
  12. 两人共用计算机,双人共享一台电脑主机 两个人同时使用一台电脑主机
  13. MQTT Java 客户端
  14. 欧冠之王!曼联3球大逆转,球王C罗再度绝杀救主!
  15. 计算机应用基础免费文档课件,计算机应用基础的课件.doc
  16. 用excel将有规律的数据随机打乱
  17. Oracle ORA-00955名称已由现有对象使用
  18. 导出excel 并且处理长数字,处理科学计数法,以文本形式存储的数字
  19. ApacheCN 公众号文章汇总 2019.9
  20. V模型、W模型、H模型

热门文章

  1. 电子商务平台到底是什么?这就告诉你!
  2. 华为ensp 401 错误解决方案
  3. java实现数据结构基数排序_数据结构与算法——基数排序简单Java实现
  4. 计算机中的二进制实验报告,大学计算机实验报告(共5篇).doc
  5. HTML经过按钮时按钮变大,html – 调整按钮大小
  6. 【19调剂】东北林业大学森林工程邢艳秋老师调剂信息
  7. 电阻、电感、电容元件的交流电路
  8. 北京交通大学计算机考研02103复试经验分享
  9. wav文件提取音频数据_python
  10. POJ 3278 Catch That Cow java 二分法 加 组合算法